diff options
| author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2020-02-22 12:03:39 -0500 |
|---|---|---|
| committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2020-02-22 12:03:39 -0500 |
| commit | 66079f2253a0c81bb33c1fee848a6cd2222d43d9 (patch) | |
| tree | ca5fdd5f27c24f8d90665cb369e50f4580ce24fc /src/SMAPI | |
| parent | c8d627cdf2ae3126584ec2500877ff19987db17f (diff) | |
| parent | 585b23797e262073e0738069eff61e90819216b7 (diff) | |
| download | SMAPI-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.cs | 55 | ||||
| -rw-r--r-- | src/SMAPI/Framework/Content/AssetDataForImage.cs | 17 | ||||
| -rw-r--r-- | src/SMAPI/Framework/ContentCoordinator.cs | 4 | ||||
| -rw-r--r-- | src/SMAPI/Framework/ContentManagers/GameContentManager.cs | 17 | ||||
| -rw-r--r-- | src/SMAPI/Framework/ContentManagers/ModContentManager.cs | 142 | ||||
| -rw-r--r-- | src/SMAPI/Framework/Input/SInputState.cs | 53 | ||||
| -rw-r--r-- | src/SMAPI/Framework/ModHelpers/ContentHelper.cs | 8 | ||||
| -rw-r--r-- | src/SMAPI/Framework/ModHelpers/InputHelper.cs | 7 | ||||
| -rw-r--r-- | src/SMAPI/Framework/Networking/ModMessageModel.cs | 2 | ||||
| -rw-r--r-- | src/SMAPI/Framework/SGame.cs | 166 | ||||
| -rw-r--r-- | src/SMAPI/Framework/SMultiplayer.cs | 84 | ||||
| -rw-r--r-- | src/SMAPI/IAssetDataForImage.cs | 6 | ||||
| -rw-r--r-- | src/SMAPI/IInputHelper.cs | 4 | ||||
| -rw-r--r-- | src/SMAPI/Metadata/CoreAssetPropagator.cs | 7 | ||||
| -rw-r--r-- | src/SMAPI/SButtonState.cs (renamed from src/SMAPI/Framework/Input/InputStatus.cs) | 14 | ||||
| -rw-r--r-- | src/SMAPI/SMAPI.csproj | 4 | ||||
| -rw-r--r-- | src/SMAPI/i18n/it.json | 3 |
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) |
