summaryrefslogtreecommitdiff
path: root/src/SMAPI
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-02-22 12:03:39 -0500
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-02-22 12:03:39 -0500
commit66079f2253a0c81bb33c1fee848a6cd2222d43d9 (patch)
treeca5fdd5f27c24f8d90665cb369e50f4580ce24fc /src/SMAPI
parentc8d627cdf2ae3126584ec2500877ff19987db17f (diff)
parent585b23797e262073e0738069eff61e90819216b7 (diff)
downloadSMAPI-66079f2253a0c81bb33c1fee848a6cd2222d43d9.tar.gz
SMAPI-66079f2253a0c81bb33c1fee848a6cd2222d43d9.tar.bz2
SMAPI-66079f2253a0c81bb33c1fee848a6cd2222d43d9.zip
Merge branch 'develop' into stable
Diffstat (limited to 'src/SMAPI')
-rw-r--r--src/SMAPI/Constants.cs55
-rw-r--r--src/SMAPI/Framework/Content/AssetDataForImage.cs17
-rw-r--r--src/SMAPI/Framework/ContentCoordinator.cs4
-rw-r--r--src/SMAPI/Framework/ContentManagers/GameContentManager.cs17
-rw-r--r--src/SMAPI/Framework/ContentManagers/ModContentManager.cs142
-rw-r--r--src/SMAPI/Framework/Input/SInputState.cs53
-rw-r--r--src/SMAPI/Framework/ModHelpers/ContentHelper.cs8
-rw-r--r--src/SMAPI/Framework/ModHelpers/InputHelper.cs7
-rw-r--r--src/SMAPI/Framework/Networking/ModMessageModel.cs2
-rw-r--r--src/SMAPI/Framework/SGame.cs166
-rw-r--r--src/SMAPI/Framework/SMultiplayer.cs84
-rw-r--r--src/SMAPI/IAssetDataForImage.cs6
-rw-r--r--src/SMAPI/IInputHelper.cs4
-rw-r--r--src/SMAPI/Metadata/CoreAssetPropagator.cs7
-rw-r--r--src/SMAPI/SButtonState.cs (renamed from src/SMAPI/Framework/Input/InputStatus.cs)14
-rw-r--r--src/SMAPI/SMAPI.csproj4
-rw-r--r--src/SMAPI/i18n/it.json3
17 files changed, 389 insertions, 204 deletions
diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs
index 201d3166..670dc494 100644
--- a/src/SMAPI/Constants.cs
+++ b/src/SMAPI/Constants.cs
@@ -20,7 +20,7 @@ namespace StardewModdingAPI
** Public
****/
/// <summary>SMAPI's current semantic version.</summary>
- public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.2.0");
+ public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.3.0");
/// <summary>The minimum supported version of Stardew Valley.</summary>
public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.4.1");
@@ -115,26 +115,59 @@ namespace StardewModdingAPI
/// <returns>Returns the compatible SMAPI version, or <c>null</c> if none was found.</returns>
internal static ISemanticVersion GetCompatibleApiVersion(ISemanticVersion version)
{
+ // This covers all officially supported public game updates. It might seem like version
+ // ranges would be better, but the given SMAPI versions may not be compatible with
+ // intermediate unlisted versions (e.g. private beta updates).
+ //
+ // Nonstandard versions are normalized by GameVersion (e.g. 1.07 => 1.0.7).
switch (version.ToString())
{
+ case "1.4.1":
+ case "1.4.0":
+ return new SemanticVersion("3.0.1");
+
case "1.3.36":
- return new SemanticVersion(2, 11, 2);
+ return new SemanticVersion("2.11.2");
- case "1.3.32":
case "1.3.33":
- return new SemanticVersion(2, 10, 2);
+ case "1.3.32":
+ return new SemanticVersion("2.10.2");
case "1.3.28":
- return new SemanticVersion(2, 7, 0);
+ return new SemanticVersion("2.7.0");
- case "1.2.30":
- case "1.2.31":
- case "1.2.32":
case "1.2.33":
- return new SemanticVersion(2, 5, 5);
- }
+ case "1.2.32":
+ case "1.2.31":
+ case "1.2.30":
+ return new SemanticVersion("2.5.5");
+
+ case "1.2.29":
+ case "1.2.28":
+ case "1.2.27":
+ case "1.2.26":
+ return new SemanticVersion("1.13.1");
+
+ case "1.1.1":
+ case "1.1.0":
+ return new SemanticVersion("1.9.0");
+
+ case "1.0.7.1":
+ case "1.0.7":
+ case "1.0.6":
+ case "1.0.5.2":
+ case "1.0.5.1":
+ case "1.0.5":
+ case "1.0.4":
+ case "1.0.3":
+ case "1.0.2":
+ case "1.0.1":
+ case "1.0.0":
+ return new SemanticVersion("0.40.0");
- return null;
+ default:
+ return null;
+ }
}
/// <summary>Get metadata for mapping assemblies to the current platform.</summary>
diff --git a/src/SMAPI/Framework/Content/AssetDataForImage.cs b/src/SMAPI/Framework/Content/AssetDataForImage.cs
index aa615a0b..44a97136 100644
--- a/src/SMAPI/Framework/Content/AssetDataForImage.cs
+++ b/src/SMAPI/Framework/Content/AssetDataForImage.cs
@@ -1,6 +1,7 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
+using StardewValley;
namespace StardewModdingAPI.Framework.Content
{
@@ -102,5 +103,21 @@ namespace StardewModdingAPI.Framework.Content
// patch target texture
target.SetData(0, targetArea, sourceData, 0, pixelCount);
}
+
+ /// <summary>Extend the image if needed to fit the given size. Note that this is an expensive operation, creates a new texture instance, and that extending a spritesheet horizontally may cause game errors or bugs.</summary>
+ /// <param name="minWidth">The minimum texture width.</param>
+ /// <param name="minHeight">The minimum texture height.</param>
+ /// <returns>Whether the texture was resized.</returns>
+ public bool ExtendImage(int minWidth, int minHeight)
+ {
+ if (this.Data.Width >= minWidth && this.Data.Height >= minHeight)
+ return false;
+
+ Texture2D original = this.Data;
+ Texture2D texture = new Texture2D(Game1.graphics.GraphicsDevice, Math.Max(original.Width, minWidth), Math.Max(original.Height, minHeight));
+ this.ReplaceWith(texture);
+ this.PatchImage(original);
+ return true;
+ }
}
}
diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs
index 2fd31263..0b1ccc3c 100644
--- a/src/SMAPI/Framework/ContentCoordinator.cs
+++ b/src/SMAPI/Framework/ContentCoordinator.cs
@@ -112,9 +112,10 @@ namespace StardewModdingAPI.Framework
/// <summary>Get a new content manager which handles reading files from a SMAPI mod folder with support for unpacked files.</summary>
/// <param name="name">A name for the mod manager. Not guaranteed to be unique.</param>
+ /// <param name="modName">The mod display name to show in errors.</param>
/// <param name="rootDirectory">The root directory to search for content (or <c>null</c> for the default).</param>
/// <param name="gameContentManager">The game content manager used for map tilesheets not provided by the mod.</param>
- public ModContentManager CreateModContentManager(string name, string rootDirectory, IContentManager gameContentManager)
+ public ModContentManager CreateModContentManager(string name, string modName, string rootDirectory, IContentManager gameContentManager)
{
return this.ContentManagerLock.InWriteLock(() =>
{
@@ -123,6 +124,7 @@ namespace StardewModdingAPI.Framework
gameContentManager: gameContentManager,
serviceProvider: this.MainContentManager.ServiceProvider,
rootDirectory: rootDirectory,
+ modName: modName,
currentCulture: this.MainContentManager.CurrentCulture,
coordinator: this,
monitor: this.Monitor,
diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
index eecdda74..eaaf0e6f 100644
--- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
@@ -2,12 +2,15 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using System.Reflection;
using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI.Framework.Content;
using StardewModdingAPI.Framework.Exceptions;
using StardewModdingAPI.Framework.Reflection;
using StardewModdingAPI.Framework.Utilities;
using StardewValley;
+using xTile;
namespace StardewModdingAPI.Framework.ContentManagers
{
@@ -337,6 +340,20 @@ namespace StardewModdingAPI.Framework.ContentManagers
{
IAssetData GetNewData(object data) => new AssetDataForObject(info, data, this.AssertAndNormalizeAssetName);
+ // special case: if the asset was loaded with a more general type like 'object', call editors with the actual type instead.
+ {
+ Type actualType = asset.Data.GetType();
+ Type actualOpenType = actualType.IsGenericType ? actualType.GetGenericTypeDefinition() : null;
+
+ if (typeof(T) != actualType && (actualOpenType == typeof(Dictionary<,>) || actualOpenType == typeof(List<>) || actualType == typeof(Texture2D) || actualType == typeof(Map)))
+ {
+ return (IAssetData)this.GetType()
+ .GetMethod(nameof(this.ApplyEditors), BindingFlags.NonPublic | BindingFlags.Instance)
+ .MakeGenericMethod(actualType)
+ .Invoke(this, new object[] { info, asset });
+ }
+ }
+
// edit asset
foreach (var entry in this.Editors)
{
diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
index 0a526fc8..7d274eb7 100644
--- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
@@ -26,6 +26,9 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <summary>Encapsulates SMAPI's JSON file parsing.</summary>
private readonly JsonHelper JsonHelper;
+ /// <summary>The mod display name to show in errors.</summary>
+ private readonly string ModName;
+
/// <summary>The game content manager used for map tilesheets not provided by the mod.</summary>
private readonly IContentManager GameContentManager;
@@ -40,6 +43,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <param name="name">A name for the mod manager. Not guaranteed to be unique.</param>
/// <param name="gameContentManager">The game content manager used for map tilesheets not provided by the mod.</param>
/// <param name="serviceProvider">The service provider to use to locate services.</param>
+ /// <param name="modName">The mod display name to show in errors.</param>
/// <param name="rootDirectory">The root directory to search for content.</param>
/// <param name="currentCulture">The current culture for which to localize content.</param>
/// <param name="coordinator">The central coordinator which manages content managers.</param>
@@ -47,11 +51,12 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <param name="reflection">Simplifies access to private code.</param>
/// <param name="jsonHelper">Encapsulates SMAPI's JSON file parsing.</param>
/// <param name="onDisposing">A callback to invoke when the content manager is being disposed.</param>
- public ModContentManager(string name, IContentManager gameContentManager, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, JsonHelper jsonHelper, Action<BaseContentManager> onDisposing)
+ public ModContentManager(string name, IContentManager gameContentManager, IServiceProvider serviceProvider, string modName, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, JsonHelper jsonHelper, Action<BaseContentManager> onDisposing)
: base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, isNamespaced: true)
{
this.GameContentManager = gameContentManager;
this.JsonHelper = jsonHelper;
+ this.ModName = modName;
}
/// <summary>Load an asset that has been processed by the content pipeline.</summary>
@@ -248,8 +253,8 @@ namespace StardewModdingAPI.Framework.ContentManagers
texture.GetData(data);
for (int i = 0; i < data.Length; i++)
{
- if (data[i].A == 0)
- continue; // no need to change fully transparent pixels
+ if (data[i].A == byte.MinValue || data[i].A == byte.MaxValue)
+ continue; // no need to change fully transparent/opaque pixels
data[i] = Color.FromNonPremultiplied(data[i].ToVector4());
}
@@ -297,98 +302,99 @@ namespace StardewModdingAPI.Framework.ContentManagers
foreach (TileSheet tilesheet in map.TileSheets)
{
string imageSource = tilesheet.ImageSource;
+ string errorPrefix = $"{this.ModName} loaded map '{relativeMapPath}' with invalid tilesheet path '{imageSource}'.";
// validate tilesheet path
if (Path.IsPathRooted(imageSource) || PathUtilities.GetSegments(imageSource).Contains(".."))
- throw new ContentLoadException($"The '{imageSource}' tilesheet couldn't be loaded. Tilesheet paths must be a relative path without directory climbing (../).");
-
- // get seasonal name (if applicable)
- string seasonalImageSource = null;
- if (isOutdoors && Context.IsSaveLoaded && Game1.currentSeason != null)
- {
- string filename = Path.GetFileName(imageSource) ?? throw new InvalidOperationException($"The '{imageSource}' tilesheet couldn't be loaded: filename is unexpectedly null.");
- bool hasSeasonalPrefix =
- filename.StartsWith("spring_", StringComparison.CurrentCultureIgnoreCase)
- || filename.StartsWith("summer_", StringComparison.CurrentCultureIgnoreCase)
- || filename.StartsWith("fall_", StringComparison.CurrentCultureIgnoreCase)
- || filename.StartsWith("winter_", StringComparison.CurrentCultureIgnoreCase);
- if (hasSeasonalPrefix && !filename.StartsWith(Game1.currentSeason + "_"))
- {
- string dirPath = imageSource.Substring(0, imageSource.LastIndexOf(filename, StringComparison.CurrentCultureIgnoreCase));
- seasonalImageSource = $"{dirPath}{Game1.currentSeason}_{filename.Substring(filename.IndexOf("_", StringComparison.CurrentCultureIgnoreCase) + 1)}";
- }
- }
+ throw new SContentLoadException($"{errorPrefix} Tilesheet paths must be a relative path without directory climbing (../).");
// load best match
try
{
- string key =
- this.GetTilesheetAssetName(relativeMapFolder, seasonalImageSource)
- ?? this.GetTilesheetAssetName(relativeMapFolder, imageSource);
- if (key != null)
- {
- tilesheet.ImageSource = key;
- continue;
- }
+ if (!this.TryGetTilesheetAssetName(relativeMapFolder, imageSource, isOutdoors, out string assetName, out string error))
+ throw new SContentLoadException($"{errorPrefix} {error}");
+
+ tilesheet.ImageSource = assetName;
}
- catch (Exception ex)
+ catch (Exception ex) when (!(ex is SContentLoadException))
{
- throw new ContentLoadException($"The '{imageSource}' tilesheet couldn't be loaded relative to either map file or the game's content folder.", ex);
+ throw new SContentLoadException($"{errorPrefix} The tilesheet couldn't be loaded.", ex);
}
-
- // none found
- throw new ContentLoadException($"The '{imageSource}' tilesheet couldn't be loaded relative to either map file or the game's content folder.");
}
}
/// <summary>Get the actual asset name for a tilesheet.</summary>
/// <param name="modRelativeMapFolder">The folder path containing the map, relative to the mod folder.</param>
- /// <param name="imageSource">The tilesheet image source to load.</param>
- /// <returns>Returns the asset name.</returns>
+ /// <param name="originalPath">The tilesheet path to load.</param>
+ /// <param name="willSeasonalize">Whether the game will apply seasonal logic to the tilesheet.</param>
+ /// <param name="assetName">The found asset name.</param>
+ /// <param name="error">A message indicating why the file couldn't be loaded.</param>
+ /// <returns>Returns whether the asset name was found.</returns>
/// <remarks>See remarks on <see cref="FixCustomTilesheetPaths"/>.</remarks>
- private string GetTilesheetAssetName(string modRelativeMapFolder, string imageSource)
+ private bool TryGetTilesheetAssetName(string modRelativeMapFolder, string originalPath, bool willSeasonalize, out string assetName, out string error)
{
- if (imageSource == null)
- return null;
+ assetName = null;
+ error = null;
+
+ // nothing to do
+ if (string.IsNullOrWhiteSpace(originalPath))
+ {
+ assetName = originalPath;
+ return true;
+ }
- // check relative to map file
+ // parse path
+ string filename = Path.GetFileName(originalPath);
+ bool isSeasonal = filename.StartsWith("spring_", StringComparison.CurrentCultureIgnoreCase)
+ || filename.StartsWith("summer_", StringComparison.CurrentCultureIgnoreCase)
+ || filename.StartsWith("fall_", StringComparison.CurrentCultureIgnoreCase)
+ || filename.StartsWith("winter_", StringComparison.CurrentCultureIgnoreCase);
+ string relativePath = originalPath;
+ if (willSeasonalize && isSeasonal)
{
- string localKey = Path.Combine(modRelativeMapFolder, imageSource);
- FileInfo localFile = this.GetModFile(localKey);
- if (localFile.Exists)
- return this.GetInternalAssetKey(localKey);
+ string dirPath = Path.GetDirectoryName(originalPath);
+ relativePath = Path.Combine(dirPath, $"{Game1.currentSeason}_{filename.Substring(filename.IndexOf("_", StringComparison.CurrentCultureIgnoreCase) + 1)}");
}
- // check relative to content folder
+ // get relative to map file
{
- foreach (string candidateKey in new[] { imageSource, Path.Combine("Maps", imageSource) })
+ string localKey = Path.Combine(modRelativeMapFolder, relativePath);
+ if (this.GetModFile(localKey).Exists)
+ {
+ assetName = this.GetInternalAssetKey(localKey);
+ return true;
+ }
+ }
+
+ // get from game assets
+ {
+ string contentKey = Path.Combine("Maps", relativePath);
+ if (contentKey.EndsWith(".png"))
+ contentKey = contentKey.Substring(0, contentKey.Length - 4);
+
+ try
+ {
+ this.GameContentManager.Load<Texture2D>(contentKey, this.Language, useCache: true); // no need to bypass cache here, since we're not storing the asset
+ assetName = contentKey;
+ return true;
+ }
+ catch
{
- string contentKey = candidateKey.EndsWith(".png")
- ? candidateKey.Substring(0, candidateKey.Length - 4)
- : candidateKey;
-
- try
- {
- this.GameContentManager.Load<Texture2D>(contentKey, this.Language, useCache: true); // no need to bypass cache here, since we're not storing the asset
- return contentKey;
- }
- catch
- {
- // ignore file-not-found errors
- // TODO: while it's useful to suppress an asset-not-found error here to avoid
- // confusion, this is a pretty naive approach. Even if the file doesn't exist,
- // the file may have been loaded through an IAssetLoader which failed. So even
- // if the content file doesn't exist, that doesn't mean the error here is a
- // content-not-found error. Unfortunately XNA doesn't provide a good way to
- // detect the error type.
- if (this.GetContentFolderFileExists(contentKey))
- throw;
- }
+ // ignore file-not-found errors
+ // TODO: while it's useful to suppress an asset-not-found error here to avoid
+ // confusion, this is a pretty naive approach. Even if the file doesn't exist,
+ // the file may have been loaded through an IAssetLoader which failed. So even
+ // if the content file doesn't exist, that doesn't mean the error here is a
+ // content-not-found error. Unfortunately XNA doesn't provide a good way to
+ // detect the error type.
+ if (this.GetContentFolderFileExists(contentKey))
+ throw;
}
}
// not found
- return null;
+ error = "The tilesheet couldn't be found relative to either map file or the game's content folder.";
+ return false;
}
/// <summary>Get whether a file from the game's content folder exists.</summary>
diff --git a/src/SMAPI/Framework/Input/SInputState.cs b/src/SMAPI/Framework/Input/SInputState.cs
index 84cea36c..4eaa9ca6 100644
--- a/src/SMAPI/Framework/Input/SInputState.cs
+++ b/src/SMAPI/Framework/Input/SInputState.cs
@@ -49,7 +49,7 @@ namespace StardewModdingAPI.Framework.Input
public ICursorPosition CursorPosition => this.CursorPositionImpl;
/// <summary>The buttons which were pressed, held, or released.</summary>
- public IDictionary<SButton, InputStatus> ActiveButtons { get; private set; } = new Dictionary<SButton, InputStatus>();
+ public IDictionary<SButton, SButtonState> ActiveButtons { get; private set; } = new Dictionary<SButton, SButtonState>();
/// <summary>The buttons to suppress when the game next handles input. Each button is suppressed until it's released.</summary>
public HashSet<SButton> SuppressButtons { get; } = new HashSet<SButton>();
@@ -75,7 +75,7 @@ namespace StardewModdingAPI.Framework.Input
[Obsolete("This method should only be called by the game itself.")]
public override void Update() { }
- /// <summary>Update the current button statuses for the given tick.</summary>
+ /// <summary>Update the current button states for the given tick.</summary>
public void TrueUpdate()
{
try
@@ -86,7 +86,7 @@ namespace StardewModdingAPI.Framework.Input
GamePadState realController = GamePad.GetState(PlayerIndex.One);
KeyboardState realKeyboard = Keyboard.GetState();
MouseState realMouse = Mouse.GetState();
- var activeButtons = this.DeriveStatuses(this.ActiveButtons, realKeyboard, realMouse, realController);
+ var activeButtons = this.DeriveStates(this.ActiveButtons, realKeyboard, realMouse, realController);
Vector2 cursorAbsolutePos = new Vector2((realMouse.X * zoomMultiplier) + Game1.viewport.X, (realMouse.Y * zoomMultiplier) + Game1.viewport.Y);
Vector2? playerTilePos = Context.IsPlayerFree ? Game1.player.getTileLocation() : (Vector2?)null;
@@ -102,7 +102,7 @@ namespace StardewModdingAPI.Framework.Input
}
// update suppressed states
- this.SuppressButtons.RemoveWhere(p => !this.GetStatus(activeButtons, p).IsDown());
+ this.SuppressButtons.RemoveWhere(p => !this.GetState(activeButtons, p).IsDown());
this.UpdateSuppression();
}
catch (InvalidOperationException)
@@ -159,7 +159,7 @@ namespace StardewModdingAPI.Framework.Input
/// <param name="button">The button to check.</param>
public bool IsDown(SButton button)
{
- return this.GetStatus(this.ActiveButtons, button).IsDown();
+ return this.GetState(this.ActiveButtons, button).IsDown();
}
/// <summary>Get whether any of the given buttons were pressed or held.</summary>
@@ -169,6 +169,13 @@ namespace StardewModdingAPI.Framework.Input
return buttons.Any(button => this.IsDown(button.ToSButton()));
}
+ /// <summary>Get the state of a button.</summary>
+ /// <param name="button">The button to check.</param>
+ public SButtonState GetState(SButton button)
+ {
+ return this.GetState(this.ActiveButtons, button);
+ }
+
/*********
** Private methods
@@ -198,7 +205,7 @@ namespace StardewModdingAPI.Framework.Input
/// <param name="keyboardState">The game's keyboard state for the current tick.</param>
/// <param name="mouseState">The game's mouse state for the current tick.</param>
/// <param name="gamePadState">The game's controller state for the current tick.</param>
- private void SuppressGivenStates(IDictionary<SButton, InputStatus> activeButtons, ref KeyboardState keyboardState, ref MouseState mouseState, ref GamePadState gamePadState)
+ private void SuppressGivenStates(IDictionary<SButton, SButtonState> activeButtons, ref KeyboardState keyboardState, ref MouseState mouseState, ref GamePadState gamePadState)
{
if (this.SuppressButtons.Count == 0)
return;
@@ -245,48 +252,48 @@ namespace StardewModdingAPI.Framework.Input
}
}
- /// <summary>Get the status of all pressed or released buttons relative to their previous status.</summary>
- /// <param name="previousStatuses">The previous button statuses.</param>
+ /// <summary>Get the state of all pressed or released buttons relative to their previous state.</summary>
+ /// <param name="previousStates">The previous button states.</param>
/// <param name="keyboard">The keyboard state.</param>
/// <param name="mouse">The mouse state.</param>
/// <param name="controller">The controller state.</param>
- private IDictionary<SButton, InputStatus> DeriveStatuses(IDictionary<SButton, InputStatus> previousStatuses, KeyboardState keyboard, MouseState mouse, GamePadState controller)
+ private IDictionary<SButton, SButtonState> DeriveStates(IDictionary<SButton, SButtonState> previousStates, KeyboardState keyboard, MouseState mouse, GamePadState controller)
{
- IDictionary<SButton, InputStatus> activeButtons = new Dictionary<SButton, InputStatus>();
+ IDictionary<SButton, SButtonState> activeButtons = new Dictionary<SButton, SButtonState>();
// handle pressed keys
SButton[] down = this.GetPressedButtons(keyboard, mouse, controller).ToArray();
foreach (SButton button in down)
- activeButtons[button] = this.DeriveStatus(this.GetStatus(previousStatuses, button), isDown: true);
+ activeButtons[button] = this.DeriveState(this.GetState(previousStates, button), isDown: true);
// handle released keys
- foreach (KeyValuePair<SButton, InputStatus> prev in previousStatuses)
+ foreach (KeyValuePair<SButton, SButtonState> prev in previousStates)
{
if (prev.Value.IsDown() && !activeButtons.ContainsKey(prev.Key))
- activeButtons[prev.Key] = InputStatus.Released;
+ activeButtons[prev.Key] = SButtonState.Released;
}
return activeButtons;
}
- /// <summary>Get the status of a button relative to its previous status.</summary>
- /// <param name="oldStatus">The previous button status.</param>
+ /// <summary>Get the state of a button relative to its previous state.</summary>
+ /// <param name="oldState">The previous button state.</param>
/// <param name="isDown">Whether the button is currently down.</param>
- private InputStatus DeriveStatus(InputStatus oldStatus, bool isDown)
+ private SButtonState DeriveState(SButtonState oldState, bool isDown)
{
- if (isDown && oldStatus.IsDown())
- return InputStatus.Held;
+ if (isDown && oldState.IsDown())
+ return SButtonState.Held;
if (isDown)
- return InputStatus.Pressed;
- return InputStatus.Released;
+ return SButtonState.Pressed;
+ return SButtonState.Released;
}
- /// <summary>Get the status of a button.</summary>
+ /// <summary>Get the state of a button.</summary>
/// <param name="activeButtons">The current button states to check.</param>
/// <param name="button">The button to check.</param>
- private InputStatus GetStatus(IDictionary<SButton, InputStatus> activeButtons, SButton button)
+ private SButtonState GetState(IDictionary<SButton, SButtonState> activeButtons, SButton button)
{
- return activeButtons.TryGetValue(button, out InputStatus status) ? status : InputStatus.None;
+ return activeButtons.TryGetValue(button, out SButtonState state) ? state : SButtonState.None;
}
/// <summary>Get the buttons pressed in the given stats.</summary>
diff --git a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs
index 043ae376..e9b70845 100644
--- a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs
@@ -32,7 +32,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <summary>The friendly mod name for use in errors.</summary>
private readonly string ModName;
- /// <summary>Encapsulates monitoring and logging for a given module.</summary>
+ /// <summary>Encapsulates monitoring and logging.</summary>
private readonly IMonitor Monitor;
@@ -70,9 +70,11 @@ namespace StardewModdingAPI.Framework.ModHelpers
public ContentHelper(ContentCoordinator contentCore, string modFolderPath, string modID, string modName, IMonitor monitor)
: base(modID)
{
+ string managedAssetPrefix = contentCore.GetManagedAssetPrefix(modID);
+
this.ContentCore = contentCore;
- this.GameContentManager = contentCore.CreateGameContentManager(this.ContentCore.GetManagedAssetPrefix(modID) + ".content");
- this.ModContentManager = contentCore.CreateModContentManager(this.ContentCore.GetManagedAssetPrefix(modID), modFolderPath, this.GameContentManager);
+ this.GameContentManager = contentCore.CreateGameContentManager(managedAssetPrefix + ".content");
+ this.ModContentManager = contentCore.CreateModContentManager(managedAssetPrefix, modName, modFolderPath, this.GameContentManager);
this.ModName = modName;
this.Monitor = monitor;
}
diff --git a/src/SMAPI/Framework/ModHelpers/InputHelper.cs b/src/SMAPI/Framework/ModHelpers/InputHelper.cs
index f4cd12b6..f8ff0355 100644
--- a/src/SMAPI/Framework/ModHelpers/InputHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/InputHelper.cs
@@ -50,5 +50,12 @@ namespace StardewModdingAPI.Framework.ModHelpers
{
this.InputState.SuppressButtons.Add(button);
}
+
+ /// <summary>Get the state of a button.</summary>
+ /// <param name="button">The button to check.</param>
+ public SButtonState GetState(SButton button)
+ {
+ return this.InputState.GetState(button);
+ }
}
}
diff --git a/src/SMAPI/Framework/Networking/ModMessageModel.cs b/src/SMAPI/Framework/Networking/ModMessageModel.cs
index 7ee39863..4f694f9c 100644
--- a/src/SMAPI/Framework/Networking/ModMessageModel.cs
+++ b/src/SMAPI/Framework/Networking/ModMessageModel.cs
@@ -21,7 +21,7 @@ namespace StardewModdingAPI.Framework.Networking
/****
** Destination
****/
- /// <summary>The players who should receive the message, or <c>null</c> for all players.</summary>
+ /// <summary>The players who should receive the message.</summary>
public long[] ToPlayerIDs { get; set; }
/// <summary>The mods which should receive the message, or <c>null</c> for all mods.</summary>
diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs
index 4b346059..6b9c1365 100644
--- a/src/SMAPI/Framework/SGame.cs
+++ b/src/SMAPI/Framework/SGame.cs
@@ -635,16 +635,16 @@ namespace StardewModdingAPI.Framework
foreach (var pair in inputState.ActiveButtons)
{
SButton button = pair.Key;
- InputStatus status = pair.Value;
+ SButtonState status = pair.Value;
- if (status == InputStatus.Pressed)
+ if (status == SButtonState.Pressed)
{
if (this.Monitor.IsVerbose)
this.Monitor.Log($"Events: button {button} pressed.", LogLevel.Trace);
events.ButtonPressed.Raise(new ButtonPressedEventArgs(button, cursor, inputState));
}
- else if (status == InputStatus.Released)
+ else if (status == SButtonState.Released)
{
if (this.Monitor.IsVerbose)
this.Monitor.Log($"Events: button {button} released.", LogLevel.Trace);
@@ -893,6 +893,7 @@ namespace StardewModdingAPI.Framework
{
var events = this.Events;
+ Game1.showingHealthBar = false;
if (Game1._newDayTask != null)
{
this.GraphicsDevice.Clear(Game1.bgColor)