summaryrefslogtreecommitdiff
path: root/src/SMAPI
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2021-11-30 17:12:49 -0500
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2021-11-30 17:12:49 -0500
commit919bbe94aa027c8a4ff8db4bdb50e8e2a28c48d9 (patch)
tree5c03ee1bd3cd658586755694940ac329491d6493 /src/SMAPI
parent3ca6fb562417748c87567d6bb6915d56b2c1b57c (diff)
parentd1d09ae1df63826dd453aa0347d668f420754ed7 (diff)
downloadSMAPI-919bbe94aa027c8a4ff8db4bdb50e8e2a28c48d9.tar.gz
SMAPI-919bbe94aa027c8a4ff8db4bdb50e8e2a28c48d9.tar.bz2
SMAPI-919bbe94aa027c8a4ff8db4bdb50e8e2a28c48d9.zip
Merge branch 'beta' into develop
Diffstat (limited to 'src/SMAPI')
-rw-r--r--src/SMAPI/Constants.cs93
-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
-rw-r--r--src/SMAPI/GameFramework.cs7
-rw-r--r--src/SMAPI/IAssetDataForMap.cs3
-rw-r--r--src/SMAPI/Metadata/CoreAssetPropagator.cs13
-rw-r--r--src/SMAPI/Metadata/InstructionMetadata.cs10
-rw-r--r--src/SMAPI/PatchMapMode.cs15
-rw-r--r--src/SMAPI/Program.cs33
-rw-r--r--src/SMAPI/SMAPI.config.json2
-rw-r--r--src/SMAPI/SMAPI.csproj40
24 files changed, 322 insertions, 380 deletions
diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs
index 42c3b21b..3ae8661a 100644
--- a/src/SMAPI/Constants.cs
+++ b/src/SMAPI/Constants.cs
@@ -40,15 +40,10 @@ namespace StardewModdingAPI
internal static GamePlatform Platform { get; } = (GamePlatform)Enum.Parse(typeof(GamePlatform), LowLevelEnvironmentUtility.DetectPlatform());
/// <summary>The game framework running the game.</summary>
- internal static GameFramework GameFramework { get; } =
-#if SMAPI_FOR_XNA
- GameFramework.Xna;
-#else
- GameFramework.MonoGame;
-#endif
+ internal static GameFramework GameFramework { get; } = GameFramework.MonoGame;
/// <summary>The game's assembly name.</summary>
- internal static string GameAssemblyName => EarlyConstants.Platform == GamePlatform.Windows ? "Stardew Valley" : "StardewValley";
+ internal static string GameAssemblyName { get; } = "Stardew Valley";
/// <summary>The <see cref="Context.ScreenId"/> value which should appear in the SMAPI log, if any.</summary>
internal static int? LogScreenId { get; set; }
@@ -70,10 +65,10 @@ namespace StardewModdingAPI
public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion(EarlyConstants.RawApiVersion);
/// <summary>The minimum supported version of Stardew Valley.</summary>
- public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.5.4");
+ public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.5.5");
/// <summary>The maximum supported version of Stardew Valley.</summary>
- public static ISemanticVersion MaximumGameVersion { get; } = new GameVersion("1.5.4");
+ public static ISemanticVersion MaximumGameVersion { get; } = null;
/// <summary>The target game platform.</summary>
public static GamePlatform TargetPlatform { get; } = EarlyConstants.Platform;
@@ -240,18 +235,13 @@ namespace StardewModdingAPI
// The game assembly can have one of three names depending how the mod was compiled:
// - 'StardewValley': assembly name on Linux/macOS;
// - 'Stardew Valley': assembly name on Windows;
- // - 'Netcode': an assembly that's separate on Windows only.
- resolver.AddWithExplicitNames(AssemblyDefinition.ReadAssembly(typeof(Game1).Assembly.Location), "StardewValley", "Stardew Valley"
-#if !SMAPI_FOR_WINDOWS
- , "Netcode"
-#endif
- );
+ // - 'Netcode': an assembly that was separate on Windows only before Stardew Valley 1.5.5.
+ resolver.AddWithExplicitNames(AssemblyDefinition.ReadAssembly(typeof(Game1).Assembly.Location), "StardewValley", "Stardew Valley", "Netcode");
}
/// <summary>Get metadata for mapping assemblies to the current platform.</summary>
/// <param name="targetPlatform">The target game platform.</param>
- /// <param name="framework">The game framework running the game.</param>
- internal static PlatformAssemblyMap GetAssemblyMap(Platform targetPlatform, GameFramework framework)
+ internal static PlatformAssemblyMap GetAssemblyMap(Platform targetPlatform)
{
var removeAssemblyReferences = new List<string>();
var targetAssemblies = new List<Assembly>();
@@ -260,61 +250,26 @@ namespace StardewModdingAPI
removeAssemblyReferences.Add("StardewModdingAPI.Toolkit.CoreInterfaces");
targetAssemblies.Add(typeof(StardewModdingAPI.IManifest).Assembly);
- // get changes for platform
- if (Constants.Platform != Platform.Windows)
- {
- removeAssemblyReferences.AddRange(new[]
- {
- "Netcode",
- "Stardew Valley"
- });
- targetAssemblies.Add(
- typeof(StardewValley.Game1).Assembly // note: includes Netcode types on Linux/macOS
- );
- }
- else
+ // XNA Framework before Stardew Valley 1.5.5
+ removeAssemblyReferences.AddRange(new[]
{
- removeAssemblyReferences.Add(
- "StardewValley"
- );
- targetAssemblies.AddRange(new[]
- {
- typeof(Netcode.NetBool).Assembly,
- typeof(StardewValley.Game1).Assembly
- });
- }
+ "Microsoft.Xna.Framework",
+ "Microsoft.Xna.Framework.Game",
+ "Microsoft.Xna.Framework.Graphics",
+ "Microsoft.Xna.Framework.Xact"
+ });
+ targetAssemblies.Add(
+ typeof(Microsoft.Xna.Framework.Vector2).Assembly
+ );
- // get changes for game framework
- switch (framework)
- {
- case GameFramework.MonoGame:
- removeAssemblyReferences.AddRange(new[]
- {
- "Microsoft.Xna.Framework",
- "Microsoft.Xna.Framework.Game",
- "Microsoft.Xna.Framework.Graphics",
- "Microsoft.Xna.Framework.Xact"
- });
- targetAssemblies.Add(
- typeof(Microsoft.Xna.Framework.Vector2).Assembly
- );
- break;
-
- case GameFramework.Xna:
- removeAssemblyReferences.Add(
- "MonoGame.Framework"
- );
- targetAssemblies.AddRange(new[]
- {
- typeof(Microsoft.Xna.Framework.Vector2).Assembly,
- typeof(Microsoft.Xna.Framework.Game).Assembly,
- typeof(Microsoft.Xna.Framework.Graphics.SpriteBatch).Assembly
- });
- break;
+ // `Netcode.dll` merged into the game assembly in Stardew Valley 1.5.5
+ removeAssemblyReferences.Add(
+ "Netcode"
+ );
- default:
- throw new InvalidOperationException($"Unknown game framework '{framework}'.");
- }
+ // Stardew Valley reference
+ removeAssemblyReferences.Add("StardewValley");
+ targetAssemblies.Add(typeof(StardewValley.Game1).Assembly);
return new PlatformAssemblyMap(targetPlatform, removeAssemblyReferences.ToArray(), targetAssemblies.ToArray());
}
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 != null || Game1.gameMode == Game1.loadingMode)
+ if (Game1.gameMode == Game1.loadingMode)
{
events.UnvalidatedUpdateTicking.RaiseEmpty();
runUpdate();
@@ -766,7 +751,7 @@ namespace StardewModdingAPI.Framework
** Locale changed events
*********/
if (state.Locale.IsChanged)
- this.Monitor.Log($"Context: locale set to {state.Locale.New}.");
+ this.Monitor.Log($"Context: locale set to {state.Locale.New} ({this.ContentCore.GetLocaleCode(state.Locale.New)}).");
/*********
** Load / return-to-title events
@@ -776,7 +761,7 @@ namespace StardewModdingAPI.Framework
else if (Context.IsWorldReady && Context.LoadStage != LoadStage.Ready)
{
// print context
- string context = $"Context: loaded save '{Constants.SaveFolderName}', starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}, locale set to {this.ContentCore.Language}.";
+ string context = $"Context: loaded save '{Constants.SaveFolderName}', starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}, locale set to {this.ContentCore.GetLocale()}.";
if (Context.IsMultiplayer)
{
int onlineCount = Game1.getOnlineFarmers().Count();
@@ -1304,9 +1289,6 @@ namespace StardewModdingAPI.Framework
{
// create client
string url = this.Settings.WebApiBaseUrl;
-#if !SMAPI_FOR_WINDOWS
- url = url.Replace("https://", "http://"); // workaround for OpenSSL issues with the game's bundled Mono on Linux/macOS
-#endif
WebApiClient client = new WebApiClient(url, Constants.ApiVersion);
this.Monitor.Log("Checking for updates...");
@@ -1491,7 +1473,7 @@ namespace StardewModdingAPI.Framework
// load mods
IList<IModMetadata> skippedMods = new List<IModMetadata>();
- using (AssemblyLoader modAssemblyLoader = new AssemblyLoader(Constants.Platform, Constants.GameFramework, this.Monitor, this.Settings.ParanoidWarnings, this.Settings.RewriteMods))
+ using (AssemblyLoader modAssemblyLoader = new AssemblyLoader(Constants.Platform, this.Monitor, this.Settings.ParanoidWarnings, this.Settings.RewriteMods))
{
// init
HashSet<string> suppressUpdateChecks = new HashSet<string>(this.Settings.SuppressUpdateChecks, StringComparer.OrdinalIgnoreCase);
@@ -1701,9 +1683,8 @@ namespace StardewModdingAPI.Framework
catch (Exception ex)
{
errorReasonPhrase = "its DLL couldn't be loaded.";
- // re-enable in Stardew Valley 1.5.5
- //if (ex is BadImageFormatException && !EnvironmentUtility.Is64BitAssembly(assemblyPath))
- // errorReasonPhrase = "it needs to be updated for 64-bit mode.";
+ if (ex is BadImageFormatException && !EnvironmentUtility.Is64BitAssembly(assemblyPath))
+ errorReasonPhrase = "it needs to be updated for 64-bit mode.";
errorDetails = $"Error: {ex.GetLogSummary()}";
failReason = ModFailReason.LoadFailed;
diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs
index 4e134455..898ed1f5 100644
--- a/src/SMAPI/Framework/SGame.cs
+++ b/src/SMAPI/Framework/SGame.cs
@@ -252,7 +252,7 @@ namespace StardewModdingAPI.Framework
/// <summary>Replicate the game's draw logic with some changes for SMAPI.</summary>
/// <param name="gameTime">A snapshot of the game timing state.</param>
/// <param name="target_screen">The render target, if any.</param>
- /// <remarks>This implementation is identical to <see cref="Game1.Draw"/>, except for try..catch around menu draw code, private field references replaced by wrappers, and added events.</remarks>
+ /// <remarks>This implementation is identical to <see cref="Game1._draw"/>, except for try..catch around menu draw code, private field references replaced by wrappers, and added events.</remarks>
[SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator", Justification = "copied from game code as-is")]
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "copied from game code as-is")]
[SuppressMessage("ReSharper", "LocalVariableHidesMember", Justification = "copied from game code as-is")]
@@ -286,7 +286,7 @@ namespace StardewModdingAPI.Framework
IClickableMenu menu = Game1.activeClickableMenu;
if (menu != null)
{
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
events.Rendering.RaiseEmpty();
try
{
@@ -304,7 +304,7 @@ namespace StardewModdingAPI.Framework
}
if (Game1.overlayMenu != null)
{
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
Game1.overlayMenu.draw(Game1.spriteBatch);
Game1.spriteBatch.End();
}
@@ -315,7 +315,7 @@ namespace StardewModdingAPI.Framework
if (Game1.activeClickableMenu != null && Game1.options.showMenuBackground && Game1.activeClickableMenu.showWithoutTransparencyIfOptionIsSet() && !this.takingMapScreenshot)
{
Game1.PushUIMode();
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
events.Rendering.RaiseEmpty();
IClickableMenu curMenu = null;
@@ -346,11 +346,11 @@ namespace StardewModdingAPI.Framework
}
if (Game1.gameMode == 11)
{
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
events.Rendering.RaiseEmpty();
- Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3685"), new Vector2(16f, 16f), Microsoft.Xna.Framework.Color.HotPink);
- Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3686"), new Vector2(16f, 32f), new Microsoft.Xna.Framework.Color(0, 255, 0));
- Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.parseText(Game1.errorMessage, Game1.dialogueFont, Game1.graphics.GraphicsDevice.Viewport.Width), new Vector2(16f, 48f), Microsoft.Xna.Framework.Color.White);
+ Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3685"), new Vector2(16f, 16f), Color.HotPink);
+ Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3686"), new Vector2(16f, 32f), new Color(0, 255, 0));
+ Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.parseText(Game1.errorMessage, Game1.dialogueFont, Game1.graphics.GraphicsDevice.Viewport.Width), new Vector2(16f, 48f), Color.White);
events.Rendered.RaiseEmpty();
Game1.spriteBatch.End();
return;
@@ -368,8 +368,8 @@ namespace StardewModdingAPI.Framework
if (Game1.globalFade && !Game1.menuUp && (!Game1.nameSelectUp || Game1.messagePause))
{
Game1.PushUIMode();
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
- Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Microsoft.Xna.Framework.Color.Black * ((Game1.gameMode == 0) ? (1f - Game1.fadeToBlackAlpha) : Game1.fadeToBlackAlpha));
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
+ Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * ((Game1.gameMode == 0) ? (1f - Game1.fadeToBlackAlpha) : Game1.fadeToBlackAlpha));
Game1.spriteBatch.End();
Game1.PopUIMode();
}
@@ -388,7 +388,7 @@ namespace StardewModdingAPI.Framework
if (Game1.showingEndOfNightStuff)
{
Game1.PushUIMode();
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
events.Rendering.RaiseEmpty();
if (Game1.activeClickableMenu != null)
{
@@ -417,16 +417,16 @@ namespace StardewModdingAPI.Framework
{
Game1.PushUIMode();
base.GraphicsDevice.Clear(Game1.bgColor);
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
events.Rendering.RaiseEmpty();
string addOn = "";
for (int i = 0; (double)i < gameTime.TotalGameTime.TotalMilliseconds % 999.0 / 333.0; i++)
{
addOn += ".";
}
- string str = Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3688");
- string msg = str + addOn;
- string largestMessage = str + "... ";
+ string text = Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3688");
+ string msg = text + addOn;
+ string largestMessage = text + "... ";
int msgw = SpriteText.getWidthOfString(largestMessage);
int msgh = 64;
int msgx = 64;
@@ -442,7 +442,7 @@ namespace StardewModdingAPI.Framework
byte batchOpens = 0; // used for rendering event
if (Game1.gameMode == 0)
{
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
if (++batchOpens == 1)
events.Rendering.RaiseEmpty();
}
@@ -456,7 +456,7 @@ namespace StardewModdingAPI.Framework
if (Game1.drawLighting)
{
Game1.SetRenderTarget(Game1.lightmap);
- base.GraphicsDevice.Clear(Microsoft.Xna.Framework.Color.White * 0f);
+ base.GraphicsDevice.Clear(Color.White * 0f);
Matrix lighting_matrix = Matrix.Identity;
if (this.useUnscaledLighting)
{
@@ -465,13 +465,13 @@ namespace StardewModdingAPI.Framework
Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, null, null, null, lighting_matrix);
if (++batchOpens == 1)
events.Rendering.RaiseEmpty();
- Microsoft.Xna.Framework.Color lighting = (Game1.currentLocation.Name.StartsWith("UndergroundMine") && Game1.currentLocation is MineShaft) ? (Game1.currentLocation as MineShaft).getLightingColor(gameTime) : ((Game1.ambientLight.Equals(Microsoft.Xna.Framework.Color.White) || (Game1.IsRainingHere() && (bool)Game1.currentLocation.isOutdoors)) ? Game1.outdoorLight : Game1.ambientLight);
+ Color lighting = ((Game1.currentLocation.Name.StartsWith("UndergroundMine") && Game1.currentLocation is MineShaft) ? (Game1.currentLocation as MineShaft).getLightingColor(gameTime) : ((Game1.ambientLight.Equals(Color.White) || (Game1.IsRainingHere() && (bool)Game1.currentLocation.isOutdoors)) ? Game1.outdoorLight : Game1.ambientLight));
float light_multiplier = 1f;
if (Game1.player.hasBuff(26))
{
- if (lighting == Microsoft.Xna.Framework.Color.White)
+ if (lighting == Color.White)
{
- lighting = new Microsoft.Xna.Framework.Color(0.75f, 0.75f, 0.75f);
+ lighting = new Color(0.75f, 0.75f, 0.75f);
}
else
{
@@ -504,12 +504,8 @@ namespace StardewModdingAPI.Framework
Game1.spriteBatch.End();
Game1.SetRenderTarget(target_screen);
}
- if (Game1.bloomDay && Game1.bloom != null)
- {
- Game1.bloom.BeginDraw();
- }
base.GraphicsDevice.Clear(Game1.bgColor);
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
if (++batchOpens == 1)
events.Rendering.RaiseEmpty();
events.RenderingWorld.RaiseEmpty();
@@ -522,10 +518,10 @@ namespace StardewModdingAPI.Framework
Game1.currentLocation.Map.GetLayer("Back").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, wrapAround: false, 4);
Game1.currentLocation.drawWater(Game1.spriteBatch);
Game1.spriteBatch.End();
- Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp);
Game1.currentLocation.drawFloorDecorations(Game1.spriteBatch);
Game1.spriteBatch.End();
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
this._farmerShadows.Clear();
if (Game1.currentLocation.currentEvent != null && !Game1.currentLocation.currentEvent.isFestival && Game1.currentLocation.currentEvent.farmerActors.Count > 0)
{
@@ -555,17 +551,17 @@ namespace StardewModdingAPI.Framework
{
if (!k.swimming && !k.HideShadow && !k.IsInvisible && !this.checkCharacterTilesForShadowDrawFlag(k))
{
- Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, k.GetShadowOffset() + k.Position + new Vector2((float)(k.GetSpriteWidthForPositioning() * 4) / 2f, k.GetBoundingBox().Height + ((!k.IsMonster) ? 12 : 0))), Game1.shadowTexture.Bounds, Microsoft.Xna.Framework.Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), Math.Max(0f, (4f + (float)k.yJumpOffset / 40f) * (float)k.scale), SpriteEffects.None, Math.Max(0f, (float)k.getStandingY() / 10000f) - 1E-06f);
+ Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, k.GetShadowOffset() + k.Position + new Vector2((float)(k.GetSpriteWidthForPositioning() * 4) / 2f, k.GetBoundingBox().Height + ((!k.IsMonster) ? 12 : 0))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), Math.Max(0f, (4f + (float)k.yJumpOffset / 40f) * (float)k.scale), SpriteEffects.None, Math.Max(0f, (float)k.getStandingY() / 10000f) - 1E-06f);
}
}
}
else
{
- foreach (NPC m in Game1.CurrentEvent.actors)
+ foreach (NPC l in Game1.CurrentEvent.actors)
{
- if ((Game1.CurrentEvent == null || !Game1.CurrentEvent.ShouldHideCharacter(m)) && !m.swimming && !m.HideShadow && !this.checkCharacterTilesForShadowDrawFlag(m))
+ if ((Game1.CurrentEvent == null || !Game1.CurrentEvent.ShouldHideCharacter(l)) && !l.swimming && !l.HideShadow && !this.checkCharacterTilesForShadowDrawFlag(l))
{
- Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, m.GetShadowOffset() + m.Position + new Vector2((float)(m.GetSpriteWidthForPositioning() * 4) / 2f, m.GetBoundingBox().Height + ((!m.IsMonster) ? ((m.Sprite.SpriteHeight <= 16) ? (-4) : 12) : 0))), Game1.shadowTexture.Bounds, Microsoft.Xna.Framework.Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), Math.Max(0f, 4f + (float)m.yJumpOffset / 40f) * (float)m.scale, SpriteEffects.None, Math.Max(0f, (float)m.getStandingY() / 10000f) - 1E-06f);
+ Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, l.GetShadowOffset() + l.Position + new Vector2((float)(l.GetSpriteWidthForPositioning() * 4) / 2f, l.GetBoundingBox().Height + ((!l.IsMonster) ? ((l.Sprite.SpriteHeight <= 16) ? (-4) : 12) : 0))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), Math.Max(0f, 4f + (float)l.yJumpOffset / 40f) * (float)l.scale, SpriteEffects.None, Math.Max(0f, (float)l.getStandingY() / 10000f) - 1E-06f);
}
}
}
@@ -573,7 +569,7 @@ namespace StardewModdingAPI.Framework
{
if (!Game1.multiplayer.isDisconnecting(f3.UniqueMultiplayerID) && !f3.swimming && !f3.isRidingHorse() && !f3.IsSitting() && (Game1.currentLocation == null || !this.checkCharacterTilesForShadowDrawFlag(f3)))
{
- Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(f3.GetShadowOffset() + f3.Position + new Vector2(32f, 24f)), Game1.shadowTexture.Bounds, Microsoft.Xna.Framework.Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), 4f - (((f3.running || f3.UsingTool) && f3.FarmerSprite.currentAnimationIndex > 1) ? ((float)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[f3.FarmerSprite.CurrentFrame]) * 0.5f) : 0f), SpriteEffects.None, 0f);
+ Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(f3.GetShadowOffset() + f3.Position + new Vector2(32f, 24f)), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), 4f - (((f3.running || f3.UsingTool) && f3.FarmerSprite.currentAnimationIndex > 1) ? ((float)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[f3.FarmerSprite.CurrentFrame]) * 0.5f) : 0f), SpriteEffects.None, 0f);
}
}
}
@@ -581,26 +577,26 @@ namespace StardewModdingAPI.Framework
building_layer.Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, wrapAround: false, 4);
Game1.mapDisplayDevice.EndScene();
Game1.spriteBatch.End();
- Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp);
if (!Game1.currentLocation.shouldHideCharacters())
{
if (Game1.CurrentEvent == null)
{
- foreach (NPC n in Game1.currentLocation.characters)
+ foreach (NPC m in Game1.currentLocation.characters)
{
- if (!n.swimming && !n.HideShadow && !n.isInvisible && this.checkCharacterTilesForShadowDrawFlag(n))
+ if (!m.swimming && !m.HideShadow && !m.isInvisible && this.checkCharacterTilesForShadowDrawFlag(m))
{
- Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, n.GetShadowOffset() + n.Position + new Vector2((float)(n.GetSpriteWidthForPositioning() * 4) / 2f, n.GetBoundingBox().Height + ((!n.IsMonster) ? 12 : 0))), Game1.shadowTexture.Bounds, Microsoft.Xna.Framework.Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), Math.Max(0f, (4f + (float)n.yJumpOffset / 40f) * (float)n.scale), SpriteEffects.None, Math.Max(0f, (float)n.getStandingY() / 10000f) - 1E-06f);
+ Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, m.GetShadowOffset() + m.Position + new Vector2((float)(m.GetSpriteWidthForPositioning() * 4) / 2f, m.GetBoundingBox().Height + ((!m.IsMonster) ? 12 : 0))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), Math.Max(0f, (4f + (float)m.yJumpOffset / 40f) * (float)m.scale), SpriteEffects.None, Math.Max(0f, (float)m.getStandingY() / 10000f) - 1E-06f);
}
}
}
else
{
- foreach (NPC n2 in Game1.CurrentEvent.actors)
+ foreach (NPC n in Game1.CurrentEvent.actors)
{
- if ((Game1.CurrentEvent == null || !Game1.CurrentEvent.ShouldHideCharacter(n2)) && !n2.swimming && !n2.HideShadow && this.checkCharacterTilesForShadowDrawFlag(n2))
+ if ((Game1.CurrentEvent == null || !Game1.CurrentEvent.ShouldHideCharacter(n)) && !n.swimming && !n.HideShadow && this.checkCharacterTilesForShadowDrawFlag(n))
{
- Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, n2.GetShadowOffset() + n2.Position + new Vector2((float)(n2.GetSpriteWidthForPositioning() * 4) / 2f, n2.GetBoundingBox().Height + ((!n2.IsMonster) ? 12 : 0))), Game1.shadowTexture.Bounds, Microsoft.Xna.Framework.Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), Math.Max(0f, (4f + (float)n2.yJumpOffset / 40f) * (float)n2.scale), SpriteEffects.None, Math.Max(0f, (float)n2.getStandingY() / 10000f) - 1E-06f);
+ Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, n.GetShadowOffset() + n.Position + new Vector2((float)(n.GetSpriteWidthForPositioning() * 4) / 2f, n.GetBoundingBox().Height + ((!n.IsMonster) ? 12 : 0))), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), Math.Max(0f, (4f + (float)n.yJumpOffset / 40f) * (float)n.scale), SpriteEffects.None, Math.Max(0f, (float)n.getStandingY() / 10000f) - 1E-06f);
}
}
}
@@ -609,7 +605,7 @@ namespace StardewModdingAPI.Framework
float draw_layer = Math.Max(0.0001f, f4.getDrawLayer() + 0.00011f) - 0.0001f;
if (!f4.swimming && !f4.isRidingHorse() && !f4.IsSitting() && Game1.currentLocation != null && this.checkCharacterTilesForShadowDrawFlag(f4))
{
- Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(f4.GetShadowOffset() + f4.Position + new Vector2(32f, 24f)), Game1.shadowTexture.Bounds, Microsoft.Xna.Framework.Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), 4f - (((f4.running || f4.UsingTool) && f4.FarmerSprite.currentAnimationIndex > 1) ? ((float)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[f4.FarmerSprite.CurrentFrame]) * 0.5f) : 0f), SpriteEffects.None, draw_layer);
+ Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(f4.GetShadowOffset() + f4.Position + new Vector2(32f, 24f)), Game1.shadowTexture.Bounds, Color.White, 0f, new Vector2(Game1.shadowTexture.Bounds.Center.X, Game1.shadowTexture.Bounds.Center.Y), 4f - (((f4.running || f4.UsingTool) && f4.FarmerSprite.currentAnimationIndex > 1) ? ((float)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[f4.FarmerSprite.CurrentFrame]) * 0.5f) : 0f), SpriteEffects.None, draw_layer);
}
}
}
@@ -619,7 +615,7 @@ namespace StardewModdingAPI.Framework
}
if (Game1.player.currentUpgrade != null && Game1.player.currentUpgrade.daysLeftTillUpgradeDone <= 3 && Game1.currentLocation.Name.Equals("Farm"))
{
- Game1.spriteBatch.Draw(Game1.player.currentUpgrade.workerTexture, Game1.GlobalToLocal(Game1.viewport, Game1.player.currentUpgrade.positionOfCarpenter), Game1.player.currentUpgrade.getSourceRectangle(), Microsoft.Xna.Framework.Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, (Game1.player.currentUpgrade.positionOfCarpenter.Y + 48f) / 10000f);
+ Game1.spriteBatch.Draw(Game1.player.currentUpgrade.workerTexture, Game1.GlobalToLocal(Game1.viewport, Game1.player.currentUpgrade.positionOfCarpenter), Game1.player.currentUpgrade.getSourceRectangle(), Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, (Game1.player.currentUpgrade.positionOfCarpenter.Y + 48f) / 10000f);
}
Game1.currentLocation.draw(Game1.spriteBatch);
foreach (Vector2 tile_position in Game1.crabPotOverlayTiles.Keys)
@@ -646,14 +642,14 @@ namespace StardewModdingAPI.Framework
}
if (Game1.tvStation >= 0)
{
- Game1.spriteBatch.Draw(Game1.tvStationTexture, Game1.GlobalToLocal(Game1.viewport, new Vector2(400f, 160f)), new Microsoft.Xna.Framework.Rectangle(Game1.tvStation * 24, 0, 24, 15), Microsoft.Xna.Framework.Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 1E-08f);
+ Game1.spriteBatch.Draw(Game1.tvStationTexture, Game1.GlobalToLocal(Game1.viewport, new Vector2(400f, 160f)), new Microsoft.Xna.Framework.Rectangle(Game1.tvStation * 24, 0, 24, 15), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 1E-08f);
}
if (Game1.panMode)
{
- Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle((int)Math.Floor((double)(Game1.getOldMouseX() + Game1.viewport.X) / 64.0) * 64 - Game1.viewport.X, (int)Math.Floor((double)(Game1.getOldMouseY() + Game1.viewport.Y) / 64.0) * 64 - Game1.viewport.Y, 64, 64), Microsoft.Xna.Framework.Color.Lime * 0.75f);
+ Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle((int)Math.Floor((double)(Game1.getOldMouseX() + Game1.viewport.X) / 64.0) * 64 - Game1.viewport.X, (int)Math.Floor((double)(Game1.getOldMouseY() + Game1.viewport.Y) / 64.0) * 64 - Game1.viewport.Y, 64, 64), Color.Lime * 0.75f);
foreach (Warp w in Game1.currentLocation.warps)
{
- Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(w.X * 64 - Game1.viewport.X, w.Y * 64 - Game1.viewport.Y, 64, 64), Microsoft.Xna.Framework.Color.Red * 0.75f);
+ Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(w.X * 64 - Game1.viewport.X, w.Y * 64 - Game1.viewport.Y, 64, 64), Color.Red * 0.75f);
}
}
Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch);
@@ -661,7 +657,7 @@ namespace StardewModdingAPI.Framework
Game1.mapDisplayDevice.EndScene();
Game1.currentLocation.drawAboveFrontLayer(Game1.spriteBatch);
Game1.spriteBatch.End();
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
if (Game1.currentLocation.Map.GetLayer("AlwaysFront") != null)
{
Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch);
@@ -670,7 +666,7 @@ namespace StardewModdingAPI.Framework
}
if (Game1.toolHold > 400f && Game1.player.CurrentTool.UpgradeLevel >= 1 && Game1.player.canReleaseTool)
{
- Microsoft.Xna.Framework.Color barColor = Microsoft.Xna.Framework.Color.White;
+ Color barColor = Color.White;
switch ((int)(Game1.toolHold / 600f) + 2)
{
case 1:
@@ -686,7 +682,7 @@ namespace StardewModdingAPI.Framework
barColor = Tool.iridiumColor;
break;
}
- Game1.spriteBatch.Draw(Game1.littleEffect, new Microsoft.Xna.Framework.Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X - 2, (int)Game1.player.getLocalPosition(Game1.viewport).Y - ((!Game1.player.CurrentTool.Name.Equals("Watering Can")) ? 64 : 0) - 2, (int)(Game1.toolHold % 600f * 0.08f) + 4, 12), Microsoft.Xna.Framework.Color.Black);
+ Game1.spriteBatch.Draw(Game1.littleEffect, new Microsoft.Xna.Framework.Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X - 2, (int)Game1.player.getLocalPosition(Game1.viewport).Y - ((!Game1.player.CurrentTool.Name.Equals("Watering Can")) ? 64 : 0) - 2, (int)(Game1.toolHold % 600f * 0.08f) + 4, 12), Color.Black);
Game1.spriteBatch.Draw(Game1.littleEffect, new Microsoft.Xna.Framework.Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X, (int)Game1.player.getLocalPosition(Game1.viewport).Y - ((!Game1.player.CurrentTool.Name.Equals("Watering Can")) ? 64 : 0), (int)(Game1.toolHold % 600f * 0.08f), 8), barColor);
}
if (!Game1.IsFakedBlackScreen())
@@ -699,7 +695,7 @@ namespace StardewModdingAPI.Framework
}
if (Game1.currentLocation.LightLevel > 0f && Game1.timeOfDay < 2000)
{
- Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Microsoft.Xna.Framework.Color.Black * Game1.currentLocation.LightLevel);
+ Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * Game1.currentLocation.LightLevel);
}
if (Game1.screenGlow)
{
@@ -711,51 +707,51 @@ namespace StardewModdingAPI.Framework
Game1.player.CurrentTool.draw(Game1.spriteBatch);
}
Game1.spriteBatch.End();
- Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp);
if (Game1.eventUp && Game1.currentLocation.currentEvent != null)
{
- foreach (NPC l in Game1.currentLocation.currentEvent.actors)
+ foreach (NPC n2 in Game1.currentLocation.currentEvent.actors)
{
- if (l.isEmoting)
+ if (n2.isEmoting)
{
- Vector2 emotePosition = l.getLocalPosition(Game1.viewport);
- if (l.NeedsBirdieEmoteHack())
+ Vector2 emotePosition = n2.getLocalPosition(Game1.viewport);
+ if (n2.NeedsBirdieEmoteHack())
{
emotePosition.X += 64f;
}
emotePosition.Y -= 140f;
- if (l.Age == 2)
+ if (n2.Age == 2)
{
emotePosition.Y += 32f;
}
- else if (l.Gender == 1)
+ else if (n2.Gender == 1)
{
emotePosition.Y += 10f;
}
- Game1.spriteBatch.Draw(Game1.emoteSpriteSheet, emotePosition, new Microsoft.Xna.Framework.Rectangle(l.CurrentEmoteIndex * 16 % Game1.emoteSpriteSheet.Width, l.CurrentEmoteIndex * 16 / Game1.emoteSpriteSheet.Width * 16, 16, 16), Microsoft.Xna.Framework.Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, (float)l.getStandingY() / 10000f);
+ Game1.spriteBatch.Draw(Game1.emoteSpriteSheet, emotePosition, new Microsoft.Xna.Framework.Rectangle(n2.CurrentEmoteIndex * 16 % Game1.emoteSpriteSheet.Width, n2.CurrentEmoteIndex * 16 / Game1.emoteSpriteSheet.Width * 16, 16, 16), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, (float)n2.getStandingY() / 10000f);
}
}
}
Game1.spriteBatch.End();
if (Game1.drawLighting && !Game1.IsFakedBlackScreen())
{
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, this.lightingBlend, SamplerState.LinearClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, this.lightingBlend, SamplerState.LinearClamp);
Viewport vp = base.GraphicsDevice.Viewport;
- vp.Bounds = (target_screen?.Bounds ?? base.GraphicsDevice.PresentationParameters.Bounds);
+ vp.Bounds = target_screen?.Bounds ?? base.GraphicsDevice.PresentationParameters.Bounds;
base.GraphicsDevice.Viewport = vp;
float render_zoom = Game1.options.lightingQuality / 2;
if (this.useUnscaledLighting)
{
render_zoom /= Game1.options.zoomLevel;
}
- Game1.spriteBatch.Draw(Game1.lightmap, Vector2.Zero, Game1.lightmap.Bounds, Microsoft.Xna.Framework.Color.White, 0f, Vector2.Zero, render_zoom, SpriteEffects.None, 1f);
+ Game1.spriteBatch.Draw(Game1.lightmap, Vector2.Zero, Game1.lightmap.Bounds, Color.White, 0f, Vector2.Zero, render_zoom, SpriteEffects.None, 1f);
if (Game1.IsRainingHere() && (bool)Game1.currentLocation.isOutdoors && !(Game1.currentLocation is Desert))
{
- Game1.spriteBatch.Draw(Game1.staminaRect, vp.Bounds, Microsoft.Xna.Framework.Color.OrangeRed * 0.45f);
+ Game1.spriteBatch.Draw(Game1.staminaRect, vp.Bounds, Color.OrangeRed * 0.45f);
}
Game1.spriteBatch.End();
}
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
events.RenderedWorld.RaiseEmpty();
if (Game1.drawGrid)
{
@@ -763,11 +759,11 @@ namespace StardewModdingAPI.Framework
float startingY = -Game1.viewport.Y % 64;
for (int x = startingX; x < Game1.graphics.GraphicsDevice.Viewport.Width; x += 64)
{
- Game1.spriteBatch.Draw(Game1.staminaRect, new Microsoft.Xna.Framework.Rectangle(x, (int)startingY, 1, Game1.graphics.GraphicsDevice.Viewport.Height), Microsoft.Xna.Framework.Color.Red * 0.5f);
+ Game1.spriteBatch.Draw(Game1.staminaRect, new Microsoft.Xna.Framework.Rectangle(x, (int)startingY, 1, Game1.graphics.GraphicsDevice.Viewport.Height), Color.Red * 0.5f);
}
for (float y = startingY; y < (float)Game1.graphics.GraphicsDevice.Viewport.Height; y += 64f)
{
- Game1.spriteBatch.Draw(Game1.staminaRect, new Microsoft.Xna.Framework.Rectangle(startingX, (int)y, Game1.graphics.GraphicsDevice.Viewport.Width, 1), Microsoft.Xna.Framework.Color.Red * 0.5f);
+ Game1.spriteBatch.Draw(Game1.staminaRect, new Microsoft.Xna.Framework.Rectangle(startingX, (int)y, Game1.graphics.GraphicsDevice.Viewport.Width, 1), Color.Red * 0.5f);
}
}
if (Game1.ShouldShowOnscreenUsernames() && Game1.currentLocation != null)
@@ -780,14 +776,14 @@ namespace StardewModdingAPI.Framework
}
if (!Game1.eventUp && Game1.farmEvent == null && Game1.currentBillboard == 0 && Game1.gameMode == 3 && !this.takingMapScreenshot && Game1.isOutdoorMapSmallerThanViewport())
{
- Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(0, 0, -Math.Min(Game1.viewport.X, GameRunner.MaxTextureSize), Game1.graphics.GraphicsDevice.Viewport.Height), Microsoft.Xna.Framework.Color.Black);
- Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(-Game1.viewport.X + Game1.currentLocation.map.Layers[0].LayerWidth * 64, 0, Math.Min(GameRunner.MaxTextureSize, Game1.graphics.GraphicsDevice.Viewport.Width - (-Game1.viewport.X + Game1.currentLocation.map.Layers[0].LayerWidth * 64)), Game1.graphics.GraphicsDevice.Viewport.Height), Microsoft.Xna.Framework.Color.Black);
- Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(0, 0, Game1.graphics.GraphicsDevice.Viewport.Width, -Math.Min(Game1.viewport.Y, GameRunner.MaxTextureSize)), Microsoft.Xna.Framework.Color.Black);
- Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(0, -Game1.viewport.Y + Game1.currentLocation.map.Layers[0].LayerHeight * 64, Game1.graphics.GraphicsDevice.Viewport.Width, Math.Min(GameRunner.MaxTextureSize, Game1.graphics.GraphicsDevice.Viewport.Height - (-Game1.viewport.Y + Game1.currentLocation.map.Layers[0].LayerHeight * 64))), Microsoft.Xna.Framework.Color.Black);
+ Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(0, 0, -Math.Min(Game1.viewport.X, GameRunner.MaxTextureSize), Game1.graphics.GraphicsDevice.Viewport.Height), Color.Black);
+ Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(-Game1.viewport.X + Game1.currentLocation.map.Layers[0].LayerWidth * 64, 0, Math.Min(GameRunner.MaxTextureSize, Game1.graphics.GraphicsDevice.Viewport.Width - (-Game1.viewport.X + Game1.currentLocation.map.Layers[0].LayerWidth * 64)), Game1.graphics.GraphicsDevice.Viewport.Height), Color.Black);
+ Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(0, 0, Game1.graphics.GraphicsDevice.Viewport.Width, -Math.Min(Game1.viewport.Y, GameRunner.MaxTextureSize)), Color.Black);
+ Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(0, -Game1.viewport.Y + Game1.currentLocation.map.Layers[0].LayerHeight * 64, Game1.graphics.GraphicsDevice.Viewport.Width, Math.Min(GameRunner.MaxTextureSize, Game1.graphics.GraphicsDevice.Viewport.Height - (-Game1.viewport.Y + Game1.currentLocation.map.Layers[0].LayerHeight * 64))), Color.Black);
}
Game1.spriteBatch.End();
Game1.PushUIMode();
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
if ((Game1.displayHUD || Game1.eventUp) && Game1.currentBillboard == 0 && Game1.gameMode == 3 && !Game1.freezeControls && !Game1.panMode && !Game1.HostPaused && !this.takingMapScreenshot)
{
events.RenderingHud.RaiseEmpty();
@@ -807,13 +803,13 @@ namespace StardewModdingAPI.Framework
}
Game1.spriteBatch.End();
Game1.PopUIMode();
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
}
if (Game1.farmEvent != null)
{
Game1.farmEvent.draw(Game1.spriteBatch);
Game1.spriteBatch.End();
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
}
Game1.PushUIMode();
if (Game1.dialogueUp && !Game1.nameSelectUp && !Game1.messagePause && (Game1.activeClickableMenu == null || !(Game1.activeClickableMenu is DialogueBox)) && !this.takingMapScreenshot)
@@ -822,35 +818,35 @@ namespace StardewModdingAPI.Framework
}
if (Game1.progressBar && !this.takingMapScreenshot)
{
- Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle((Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Bottom - 128, Game1.dialogueWidth, 32), Microsoft.Xna.Framework.Color.LightGray);
- Game1.spriteBatch.Draw(Game1.staminaRect, new Microsoft.Xna.Framework.Rectangle((Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Bottom - 128, (int)(Game1.pauseAccumulator / Game1.pauseTime * (float)Game1.dialogueWidth), 32), Microsoft.Xna.Framework.Color.DimGray);
+ Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle((Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Bottom - 128, Game1.dialogueWidth, 32), Color.LightGray);
+ Game1.spriteBatch.Draw(Game1.staminaRect, new Microsoft.Xna.Framework.Rectangle((Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Bottom - 128, (int)(Game1.pauseAccumulator / Game1.pauseTime * (float)Game1.dialogueWidth), 32), Color.DimGray);
}
Game1.spriteBatch.End();
Game1.PopUIMode();
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
if (Game1.eventUp && Game1.currentLocation != null && Game1.currentLocation.currentEvent != null)
{
Game1.currentLocation.currentEvent.drawAfterMap(Game1.spriteBatch);
}
if (!Game1.IsFakedBlackScreen() && Game1.IsRainingHere() && Game1.currentLocation != null && (bool)Game1.currentLocation.isOutdoors && !(Game1.currentLocation is Desert))
{
- Game1.spriteBatch.Draw(Game1.staminaRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Microsoft.Xna.Framework.Color.Blue * 0.2f);
+ Game1.spriteBatch.Draw(Game1.staminaRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Blue * 0.2f);
}
if ((Game1.fadeToBlack || Game1.globalFade) && !Game1.menuUp && (!Game1.nameSelectUp || Game1.messagePause) && !this.takingMapScreenshot)
{
Game1.spriteBatch.End();
Game1.PushUIMode();
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
- Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Microsoft.Xna.Framework.Color.Black * ((Game1.gameMode == 0) ? (1f - Game1.fadeToBlackAlpha) : Game1.fadeToBlackAlpha));
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
+ Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * ((Game1.gameMode == 0) ? (1f - Game1.fadeToBlackAlpha) : Game1.fadeToBlackAlpha));
Game1.spriteBatch.End();
Game1.PopUIMode();
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
}
else if (Game1.flashAlpha > 0f && !this.takingMapScreenshot)
{
if (Game1.options.screenFlash)
{
- Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Microsoft.Xna.Framework.Color.White * Math.Min(1f, Game1.flashAlpha));
+ Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.White * Math.Min(1f, Game1.flashAlpha));
}
Game1.flashAlpha -= 0.1f;
}
@@ -866,14 +862,14 @@ namespace StardewModdingAPI.Framework
}
Game1.spriteBatch.End();
Game1.PushUIMode();
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
foreach (TemporaryAnimatedSprite uiOverlayTempSprite in Game1.uiOverlayTempSprites)
{
uiOverlayTempSprite.draw(Game1.spriteBatch, localPosition: true);
}
Game1.spriteBatch.End();
Game1.PopUIMode();
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
}
if (Game1.debugMode)
{
@@ -905,14 +901,14 @@ namespace StardewModdingAPI.Framework
sb.Append(Game1.getMouseY() + Game1.viewport.Y);
sb.Append(" debugOutput: ");
sb.Append(Game1.debugOutput);
- Game1.spriteBatch.DrawString(Game1.smallFont, sb, new Vector2(base.GraphicsDevice.Viewport.GetTitleSafeArea().X, base.GraphicsDevice.Viewport.GetTitleSafeArea().Y + Game1.smallFont.LineSpacing * 8), Microsoft.Xna.Framework.Color.Red, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f);
+ Game1.spriteBatch.DrawString(Game1.smallFont, sb, new Vector2(base.GraphicsDevice.Viewport.GetTitleSafeArea().X, base.GraphicsDevice.Viewport.GetTitleSafeArea().Y + Game1.smallFont.LineSpacing * 8), Color.Red, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f);
}
Game1.spriteBatch.End();
Game1.PushUIMode();
- Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
+ Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
if (Game1.showKeyHelp && !this.takingMapScreenshot)
{
- Game1.spriteBatch.DrawString(Game1.smallFont, Game1.keyHelpString, new Vector2(64f, (float)(Game1.viewport.Height - 64 - (Game1.dialogueUp ? (192 + (Game1.isQuestion ? (Game1.questionChoices.Count * 64) : 0)) : 0)) - Game1.smallFont.MeasureString(Game1.keyHelpString).Y), Microsoft.Xna.Framework.Color.LightGray, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f);
+ Game1.spriteBatch.DrawString(Game1.smallFont, Game1.keyHelpString, new Vector2(64f, (float)(Game1.viewport.Height - 64 - (Game1.dialogueUp ? (192 + (Game1.isQuestion ? (Game1.questionChoices.Count * 64) : 0)) : 0)) - Game1.smallFont.MeasureString(Game1.keyHelpString).Y), Color.LightGray, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f);
}
if (Game1.activeClickableMenu != null && !this.takingMapScreenshot)
{
diff --git a/src/SMAPI/Framework/SModHooks.cs b/src/SMAPI/Framework/SModHooks.cs
index 7dafc746..101e022a 100644
--- a/src/SMAPI/Framework/SModHooks.cs
+++ b/src/SMAPI/Framework/SModHooks.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading.Tasks;
using StardewValley;
namespace StardewModdingAPI.Framework
@@ -12,15 +13,20 @@ namespace StardewModdingAPI.Framework
/// <summary>A callback to invoke before <see cref="Game1.newDayAfterFade"/> runs.</summary>
private readonly Action BeforeNewDayAfterFade;
+ /// <summary>Writes messages to the console.</summary>
+ private readonly IMonitor Monitor;
+
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
/// <param name="beforeNewDayAfterFade">A callback to invoke before <see cref="Game1.newDayAfterFade"/> runs.</param>
- public SModHooks(Action beforeNewDayAfterFade)
+ /// <param name="monitor">Writes messages to the console.</param>
+ public SModHooks(Action beforeNewDayAfterFade, IMonitor monitor)
{
this.BeforeNewDayAfterFade = beforeNewDayAfterFade;
+ this.Monitor = monitor;
}
/// <summary>A hook invoked when <see cref="Game1.newDayAfterFade"/> is called.</summary>
@@ -30,5 +36,27 @@ namespace StardewModdingAPI.Framework
this.BeforeNewDayAfterFade?.Invoke();
action();
}
+
+ /// <summary>Start an asynchronous task for the game.</summary>
+ /// <param name="task">The task to start.</param>
+ /// <param name="id">A unique key which identifies the task.</param>
+ public override Task StartTask(Task task, string id)
+ {
+ this.Monitor.Log($"Synchronizing '{id}' task...");
+ task.RunSynchronously();
+ this.Monitor.Log(" task complete.");
+ return task;
+ }
+
+ /// <summary>Start an asynchronous task for the game.</summary>
+ /// <param name="task">The task to start.</param>
+ /// <param name="id">A unique key which identifies the task.</param>
+ public override Task<T> StartTask<T>(Task<T> task, string id)
+ {
+ this.Monitor.Log($"Synchronizing '{id}' task...");
+ task.RunSynchronously();
+ this.Monitor.Log(" task complete.");
+ return task;
+ }
}
}
diff --git a/src/SMAPI/GameFramework.cs b/src/SMAPI/GameFramework.cs
index 7670ce8f..a0154329 100644
--- a/src/SMAPI/GameFramework.cs
+++ b/src/SMAPI/GameFramework.cs
@@ -1,12 +1,15 @@
+using System;
+
namespace StardewModdingAPI
{
/// <summary>The game framework running the game.</summary>
public enum GameFramework
{
- /// <summary>The XNA Framework on Windows.</summary>
+ /// <summary>The XNA Framework, previously used on Windows.</summary>
+ [Obsolete("Stardew Valley no longer uses XNA Framework on any supported platform.")]
Xna,
- /// <summary>The MonoGame framework, usually on non-Windows platforms.</summary>
+ /// <summary>The MonoGame framework.</summary>
MonoGame
}
}
diff --git a/src/SMAPI/IAssetDataForMap.cs b/src/SMAPI/IAssetDataForMap.cs
index bfaba9ba..47a33de8 100644
--- a/src/SMAPI/IAssetDataForMap.cs
+++ b/src/SMAPI/IAssetDataForMap.cs
@@ -13,6 +13,7 @@ namespace StardewModdingAPI
/// <param name="source">The map from which to copy.</param>
/// <param name="sourceArea">The tile area within the source map to copy, or <c>null</c> for the entire source map size. This must be within the bounds of the <paramref name="source"/> map.</param>
/// <param name="targetArea">The tile area within the target map to overwrite, or <c>null</c> to patch the whole map. The original content within this area will be erased. This must be within the bounds of the existing map.</param>
- void PatchMap(Map source, Rectangle? sourceArea = null, Rectangle? targetArea = null);
+ /// <param name="patchMode">Indicates how the map should be patched.</param>
+ void PatchMap(Map source, Rectangle? sourceArea = null, Rectangle? targetArea = null, PatchMapMode patchMode = PatchMapMode.Overlay);
}
}
diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs
index 7efd99a0..552bc000 100644
--- a/src/SMAPI/Metadata/CoreAssetPropagator.cs
+++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs
@@ -226,13 +226,8 @@ namespace StardewModdingAPI.Metadata
** Buildings
****/
case "buildings\\houses": // Farm
- {
- var field = reflection.GetField<Texture2D>(typeof(Farm), nameof(Farm.houseTextures));
- field.SetValue(
- this.LoadAndDisposeIfNeeded(field.GetValue(), key)
- );
- return true;
- }
+ Farm.houseTextures = this.LoadAndDisposeIfNeeded(Farm.houseTextures, key);
+ return true;
case "buildings\\houses_paintmask": // Farm
{
@@ -447,10 +442,6 @@ namespace StardewModdingAPI.Metadata
Game1.objectSpriteSheet = content.Load<Texture2D>(key);
return true;
- case "maps\\walls_and_floors": // Wallpaper
- Wallpaper.wallpaperTexture = content.Load<Texture2D>(key);
- return true;
-
/****
** Content\Minigames
****/
diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs
index 76371e50..232e54ce 100644
--- a/src/SMAPI/Metadata/InstructionMetadata.cs
+++ b/src/SMAPI/Metadata/InstructionMetadata.cs
@@ -36,9 +36,6 @@ namespace StardewModdingAPI.Metadata
// rewrite for crossplatform compatibility
if (rewriteMods)
{
- if (platformChanged)
- yield return new MethodParentRewriter(typeof(SpriteBatch), typeof(SpriteBatchFacade));
-
// rewrite for Stardew Valley 1.5
yield return new FieldReplaceRewriter(typeof(DecoratableLocation), "furniture", typeof(GameLocation), nameof(GameLocation.furniture));
yield return new FieldReplaceRewriter(typeof(Farm), "resourceClumps", typeof(GameLocation), nameof(GameLocation.resourceClumps));
@@ -48,9 +45,10 @@ namespace StardewModdingAPI.Metadata
yield return new HeuristicFieldRewriter(this.ValidateReferencesToAssemblies);
yield return new HeuristicMethodRewriter(this.ValidateReferencesToAssemblies);
- // rewrite for 64-bit mode
- // re-enable in Stardew Valley 1.5.5
- //yield return new ArchitectureAssemblyRewriter();
+ // rewrite for Stardew Valley 1.5.5
+ if (platformChanged)
+ yield return new MethodParentRewriter(typeof(SpriteBatch), typeof(SpriteBatchFacade));
+ yield return new ArchitectureAssemblyRewriter();
// detect Harmony & rewrite for SMAPI 3.12 (Harmony 1.x => 2.0 update)
yield return new HarmonyRewriter();
diff --git a/src/SMAPI/PatchMapMode.cs b/src/SMAPI/PatchMapMode.cs
new file mode 100644
index 00000000..1f1ac6a9
--- /dev/null
+++ b/src/SMAPI/PatchMapMode.cs
@@ -0,0 +1,15 @@
+namespace StardewModdingAPI
+{
+ /// <summary>Indicates how a map should be patched.</summary>
+ public enum PatchMapMode
+ {
+ /// <summary>Replace matching tiles. Target tiles missing in the source area are kept as-is.</summary>
+ Overlay,
+
+ /// <summary>Replace all tiles on layers that exist in the source map.</summary>
+ ReplaceByLayer,
+
+ /// <summary>Replace all tiles with the source map.</summary>
+ Replace
+ }
+}
diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs
index 3f97e531..67ff8322 100644
--- a/src/SMAPI/Program.cs
+++ b/src/SMAPI/Program.cs
@@ -4,8 +4,8 @@ using System.Linq;
using System.Reflection;
using System.Threading;
using StardewModdingAPI.Framework;
-using StardewModdingAPI.Toolkit.Framework;
using StardewModdingAPI.Toolkit.Serialization.Models;
+using StardewModdingAPI.Toolkit.Utilities;
namespace StardewModdingAPI
{
@@ -26,7 +26,7 @@ namespace StardewModdingAPI
/// <param name="args">The command-line arguments.</param>
public static void Main(string[] args)
{
- Console.Title = $"SMAPI {EarlyConstants.RawApiVersion} - {Console.Title}";
+ Console.Title = $"SMAPI {EarlyConstants.RawApiVersion}";
try
{
@@ -34,9 +34,10 @@ namespace StardewModdingAPI
Program.AssertGamePresent();
Program.AssertGameVersion();
Program.AssertSmapiVersions();
+ Program.AssertDepsJson();
Program.Start(args);
}
- catch (BadImageFormatException ex) when (ex.FileName == "StardewValley" || ex.FileName == "Stardew Valley") // don't use EarlyConstants.GameAssemblyName, since we want to check both possible names
+ catch (BadImageFormatException ex) when (ex.FileName == EarlyConstants.GameAssemblyName)
{
Console.WriteLine($"SMAPI failed to initialize because your game's {ex.FileName}.exe seems to be invalid.\nThis may be a pirated version which modified the executable in an incompatible way; if so, you can try a different download or buy a legitimate version.\n\nTechnical details:\n{ex}");
}
@@ -84,22 +85,10 @@ namespace StardewModdingAPI
}
catch (Exception ex)
{
- // unofficial 64-bit
- if (EarlyConstants.Platform == GamePlatform.Windows)
- {
- FileInfo linuxExecutable = new FileInfo(Path.Combine(EarlyConstants.ExecutionPath, "StardewValley.exe"));
- if (linuxExecutable.Exists && LowLevelEnvironmentUtility.Is64BitAssembly(linuxExecutable.FullName))
- Program.PrintErrorAndExit("Oops! You're running Stardew Valley in unofficial 64-bit mode, which is no longer supported. You can update to Stardew Valley 1.5.5 or later instead. See https://stardewvalleywiki.com/Modding:Migrate_to_64-bit_on_Windows for more info.");
- }
-
// file doesn't exist
if (!File.Exists(Path.Combine(EarlyConstants.ExecutionPath, $"{EarlyConstants.GameAssemblyName}.exe")))
Program.PrintErrorAndExit("Oops! SMAPI can't find the game. Make sure you're running StardewModdingAPI.exe in your game folder.");
- // Stardew Valley 1.5.5+
- if (File.Exists(Path.Combine(EarlyConstants.ExecutionPath, "Stardew Valley.dll")))
- Program.PrintErrorAndExit("Oops! You're running Stardew Valley 1.5.5 or later, but this version of SMAPI is only compatible up to Stardew Valley 1.5.4. Please check for a newer version of SMAPI: https://smapi.io.");
-
// can't load file
Program.PrintErrorAndExit(
message: "Oops! SMAPI couldn't load the game executable. The technical details below may have more info.",
@@ -143,6 +132,20 @@ namespace StardewModdingAPI
}
}
+ /// <summary>Assert that SMAPI's <c>StardewModdingAPI.deps.json</c> matches <c>Stardew Valley.deps.json</c>, fixing it if necessary.</summary>
+ /// <remarks>This is needed to resolve native DLLs like libSkiaSharp.</remarks>
+ private static void AssertDepsJson()
+ {
+ string sourcePath = Path.Combine(Constants.ExecutionPath, "Stardew Valley.deps.json");
+ string targetPath = Path.Combine(Constants.ExecutionPath, "StardewModdingAPI.deps.json");
+
+ if (!File.Exists(targetPath) || FileUtilities.GetFileHash(sourcePath) != FileUtilities.GetFileHash(targetPath))
+ {
+ File.Copy(sourcePath, targetPath, overwrite: true);
+ Program.PrintErrorAndExit($"The '{Path.GetFileName(targetPath)}' file didn't match the game's version. SMAPI fixed it automatically, but you must restart SMAPI for the change to take effect.");
+ }
+ }
+
/// <summary>Initialize SMAPI and launch the game.</summary>
/// <param name="args">The command-line arguments.</param>
/// <remarks>This method is separate from <see cref="Main"/> because that can't contain any references to assemblies loaded by <see cref="CurrentDomain_AssemblyResolve"/> (e.g. via <see cref="Constants"/>), or Mono will incorrectly show an assembly resolution error before assembly resolution is set up.</remarks>
diff --git a/src/SMAPI/SMAPI.config.json b/src/SMAPI/SMAPI.config.json
index 7b5625d6..e62c8880 100644
--- a/src/SMAPI/SMAPI.config.json
+++ b/src/SMAPI/SMAPI.config.json
@@ -76,8 +76,6 @@ copy all the settings, or you may cause bugs due to overridden changes in future
/**
* The base URL for SMAPI's web API, used to perform update checks.
- * Note: the protocol will be changed to http:// on Linux/macOS due to OpenSSL issues with the
- * game's bundled Mono.
*/
"WebApiBaseUrl": "https://smapi.io/api/",
diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj
index c147e7dc..b99028da 100644
--- a/src/SMAPI/SMAPI.csproj
+++ b/src/SMAPI/SMAPI.csproj
@@ -3,13 +3,16 @@
<AssemblyName>StardewModdingAPI</AssemblyName>
<RootNamespace>StardewModdingAPI</RootNamespace>
<Description>The modding API for Stardew Valley.</Description>
- <TargetFramework>net452</TargetFramework>
- <PlatformTarget>x86</PlatformTarget>
+ <TargetFramework>net5.0</TargetFramework>
+ <PlatformTarget>x64</PlatformTarget>
<OutputType>Exe</OutputType>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<LargeAddressAware Condition="'$(OS)' == 'Windows_NT'">true</LargeAddressAware>
<ApplicationIcon>icon.ico</ApplicationIcon>
+
+ <!--copy dependency DLLs to bin folder so we can include them in installer bundle -->
+ <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<Import Project="..\..\build\common.targets" />
@@ -19,43 +22,22 @@
<PackageReference Include="Mono.Cecil" Version="0.11.4" />
<PackageReference Include="MonoMod.Common" Version="21.6.21.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
- <PackageReference Include="Platonymous.TMXTile" Version="1.5.8" />
+ <PackageReference Include="Platonymous.TMXTile" Version="1.5.9" />
+ <PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
+ <PackageReference Include="System.Runtime.Caching" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="..\..\build\0Harmony.dll" Private="True" />
- <Reference Include="$(GameExecutableName)" HintPath="$(GamePath)\$(GameExecutableName).exe" Private="False" />
+ <Reference Include="Stardew Valley" HintPath="$(GamePath)\Stardew Valley.dll" Private="False" />
<Reference Include="StardewValley.GameData" HintPath="$(GamePath)\StardewValley.GameData.dll" Private="False" />
- <Reference Include="System.Numerics" Private="True" />
- <Reference Include="System.Runtime.Caching" Private="True" />
+ <Reference Include="BmFont" HintPath="$(GamePath)\BmFont.dll" Private="False" />
<Reference Include="GalaxyCSharp" HintPath="$(GamePath)\GalaxyCSharp.dll" Private="False" />
<Reference Include="Lidgren.Network" HintPath="$(GamePath)\Lidgren.Network.dll" Private="False" />
+ <Reference Include="MonoGame.Framework" HintPath="$(GamePath)\MonoGame.Framework.dll" Private="False" />
<Reference Include="xTile" HintPath="$(GamePath)\xTile.dll" Private="False" />
</ItemGroup>
- <!-- Windows only -->
- <ItemGroup Condition="'$(OS)' == 'Windows_NT'">
- <Reference Include="Netcode" HintPath="$(GamePath)\Netcode.dll" Private="False" />
- <Reference Include="System.Windows.Forms" />
- </ItemGroup>
-
- <!-- Game framework -->
- <Choose>
- <When Condition="$(DefineConstants.Contains(SMAPI_FOR_XNA))">
- <ItemGroup>
- <Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="False" />
- <Reference Include="Microsoft.Xna.Framework.Game, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="False" />
- <Reference Include="Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="False" />
- <Reference Include="Microsoft.Xna.Framework.Xact, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="False" />
- </ItemGroup>
- </When>
- <Otherwise>
- <ItemGroup>
- <Reference Include="MonoGame.Framework" HintPath="$(GamePath)\MonoGame.Framework.dll" Private="False" />
- </ItemGroup>
- </Otherwise>
- </Choose>
-
<ItemGroup>
<ProjectReference Include="..\SMAPI.Toolkit.CoreInterfaces\SMAPI.Toolkit.CoreInterfaces.csproj" />
<ProjectReference Include="..\SMAPI.Toolkit\SMAPI.Toolkit.csproj" />