From dab1ef6acc243726247cee57877c3b3100106522 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 20 Jun 2022 18:01:48 -0400 Subject: add flag to disable deprecated code --- src/SMAPI/Framework/Content/AssetInfo.cs | 12 ++++++++--- .../Framework/Content/AssetInterceptorChange.cs | 3 ++- src/SMAPI/Framework/ContentCoordinator.cs | 20 ++++++++++++++++-- .../ContentManagers/GameContentManager.cs | 24 +++++++++++++++++++--- src/SMAPI/Framework/ContentPack.cs | 2 ++ src/SMAPI/Framework/ModHelpers/CommandHelper.cs | 4 ++++ src/SMAPI/Framework/ModHelpers/ContentHelper.cs | 2 ++ src/SMAPI/Framework/ModHelpers/ModHelper.cs | 17 ++++++++++----- src/SMAPI/Framework/ModLoading/AssemblyLoader.cs | 4 ++++ .../ModLoading/Finders/LegacyAssemblyFinder.cs | 2 ++ .../ModLoading/InstructionHandleResult.cs | 2 ++ src/SMAPI/Framework/SCore.cs | 22 +++++++++++++++----- 12 files changed, 95 insertions(+), 19 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/Content/AssetInfo.cs b/src/SMAPI/Framework/Content/AssetInfo.cs index 773e3126..43feed27 100644 --- a/src/SMAPI/Framework/Content/AssetInfo.cs +++ b/src/SMAPI/Framework/Content/AssetInfo.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using Microsoft.Xna.Framework.Graphics; +#if SMAPI_DEPRECATED using StardewModdingAPI.Framework.Deprecations; +#endif namespace StardewModdingAPI.Framework.Content { @@ -29,6 +31,10 @@ namespace StardewModdingAPI.Framework.Content /// public IAssetName NameWithoutLocale => this.NameWithoutLocaleImpl ??= this.Name.GetBaseAssetName(); + /// + public Type DataType { get; } + +#if SMAPI_DEPRECATED /// [Obsolete($"Use {nameof(AssetInfo.Name)} or {nameof(AssetInfo.NameWithoutLocale)} instead. This property will be removed in SMAPI 4.0.0.")] public string AssetName @@ -50,9 +56,7 @@ namespace StardewModdingAPI.Framework.Content return this.NameWithoutLocale.Name; } } - - /// - public Type DataType { get; } +#endif /********* @@ -71,6 +75,7 @@ namespace StardewModdingAPI.Framework.Content this.GetNormalizedPath = getNormalizedPath; } +#if SMAPI_DEPRECATED /// [Obsolete($"Use {nameof(Name)}.{nameof(IAssetName.IsEquivalentTo)} or {nameof(AssetInfo.NameWithoutLocale)}.{nameof(IAssetName.IsEquivalentTo)} instead. This method will be removed in SMAPI 4.0.0.")] public bool AssetNameEquals(string path) @@ -90,6 +95,7 @@ namespace StardewModdingAPI.Framework.Content return this.NameWithoutLocale.IsEquivalentTo(path); } +#endif /********* diff --git a/src/SMAPI/Framework/Content/AssetInterceptorChange.cs b/src/SMAPI/Framework/Content/AssetInterceptorChange.cs index f3d4f3f4..3b5068dc 100644 --- a/src/SMAPI/Framework/Content/AssetInterceptorChange.cs +++ b/src/SMAPI/Framework/Content/AssetInterceptorChange.cs @@ -1,8 +1,8 @@ +#if SMAPI_DEPRECATED using System; using System.Reflection; using StardewModdingAPI.Internal; -#pragma warning disable CS0618 // obsolete asset interceptors deliberately supported here namespace StardewModdingAPI.Framework.Content { /// A wrapper for and for internal cache invalidation. @@ -103,3 +103,4 @@ namespace StardewModdingAPI.Framework.Content } } } +#endif diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs index 3e09ac62..9e044b44 100644 --- a/src/SMAPI/Framework/ContentCoordinator.cs +++ b/src/SMAPI/Framework/ContentCoordinator.cs @@ -12,7 +12,9 @@ using StardewModdingAPI.Framework.Content; using StardewModdingAPI.Framework.ContentManagers; using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Framework.Utilities; +#if SMAPI_DEPRECATED using StardewModdingAPI.Internal; +#endif using StardewModdingAPI.Metadata; using StardewModdingAPI.Toolkit.Serialization; using StardewModdingAPI.Toolkit.Utilities.PathLookups; @@ -84,6 +86,7 @@ namespace StardewModdingAPI.Framework /// The cached asset load/edit operations to apply, indexed by asset name. private readonly TickCacheDictionary AssetOperationsByKey = new(); +#if SMAPI_DEPRECATED /// A cache of asset operation groups created for legacy implementations. [Obsolete("This only exists to support legacy code and will be removed in SMAPI 4.0.0.")] private readonly Dictionary> LegacyLoaderCache = new(ReferenceEqualityComparer.Instance); @@ -91,6 +94,7 @@ namespace StardewModdingAPI.Framework /// A cache of asset operation groups created for legacy implementations. [Obsolete("This only exists to support legacy code and will be removed in SMAPI 4.0.0.")] private readonly Dictionary> LegacyEditorCache = new(ReferenceEqualityComparer.Instance); +#endif /********* @@ -102,6 +106,7 @@ namespace StardewModdingAPI.Framework /// The current language as a constant. public LocalizedContentManager.LanguageCode Language => this.MainContentManager.Language; +#if SMAPI_DEPRECATED /// Interceptors which provide the initial versions of matching assets. [Obsolete("This only exists to support legacy code and will be removed in SMAPI 4.0.0.")] public IList> Loaders { get; } = new List>(); @@ -109,6 +114,7 @@ namespace StardewModdingAPI.Framework /// Interceptors which edit matching assets after they're loaded. [Obsolete("This only exists to support legacy code and will be removed in SMAPI 4.0.0.")] public IList> Editors { get; } = new List>(); +#endif /// The absolute path to the . public string FullRootDirectory { get; } @@ -498,15 +504,25 @@ namespace StardewModdingAPI.Framework return invalidatedAssets.Keys; } +#if SMAPI_DEPRECATED /// Get the asset load and edit operations to apply to a given asset if it's (re)loaded now. /// The asset type. /// The asset info to load or edit. public AssetOperationGroup? GetAssetOperations(IAssetInfo info) where T : notnull +#else + /// Get the asset load and edit operations to apply to a given asset if it's (re)loaded now. + /// The asset info to load or edit. + public AssetOperationGroup? GetAssetOperations(IAssetInfo info) +#endif { return this.AssetOperationsByKey.GetOrSet( info.Name, +#if SMAPI_DEPRECATED () => this.GetAssetOperationsWithoutCache(info) +#else + () => this.RequestAssetOperations(info) +#endif ); } @@ -629,6 +645,7 @@ namespace StardewModdingAPI.Framework return map; } +#if SMAPI_DEPRECATED /// Get the asset load and edit operations to apply to a given asset if it's (re)loaded now, ignoring the cache. /// The asset type. /// The asset info to load or edit. @@ -639,7 +656,6 @@ namespace StardewModdingAPI.Framework AssetOperationGroup? group = this.RequestAssetOperations(info); // legacy load operations -#pragma warning disable CS0612, CS0618 // deprecated code if (this.Editors.Count > 0 || this.Loaders.Count > 0) { IAssetInfo legacyInfo = this.GetLegacyAssetInfo(info); @@ -738,7 +754,6 @@ namespace StardewModdingAPI.Framework ); } } -#pragma warning restore CS0612, CS0618 return group; } @@ -818,5 +833,6 @@ namespace StardewModdingAPI.Framework // else no change needed return asset; } +#endif } } diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs index 446f4a67..df7bdc59 100644 --- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs @@ -76,7 +76,11 @@ namespace StardewModdingAPI.Framework.ContentManagers // custom asset from a loader string locale = this.GetLocale(); IAssetInfo info = new AssetInfo(locale, assetName, typeof(T), this.AssertAndNormalizeAssetName); - AssetOperationGroup? operations = this.Coordinator.GetAssetOperations(info); + AssetOperationGroup? operations = this.Coordinator.GetAssetOperations +#if SMAPI_DEPRECATED + +#endif + (info); if (operations?.LoadOperations.Count > 0) { if (!this.AssertMaxOneRequiredLoader(info, operations.LoadOperations, out string? error)) @@ -129,7 +133,11 @@ namespace StardewModdingAPI.Framework.ContentManagers data = this.AssetsBeingLoaded.Track(assetName.Name, () => { IAssetInfo info = new AssetInfo(assetName.LocaleCode, assetName, typeof(T), this.AssertAndNormalizeAssetName); - AssetOperationGroup? operations = this.Coordinator.GetAssetOperations(info); + AssetOperationGroup? operations = this.Coordinator.GetAssetOperations +#if SMAPI_DEPRECATED + +#endif + (info); IAssetData asset = this.ApplyLoader(info, operations?.LoadOperations) ?? new AssetDataForObject(info, this.RawLoad(assetName, useCache), this.AssertAndNormalizeAssetName, this.Reflection); @@ -294,7 +302,11 @@ namespace StardewModdingAPI.Framework.ContentManagers ? $"Multiple mods want to provide the '{info.Name}' asset: {string.Join(", ", loaderNames)}" : $"The '{loaderNames[0]}' mod wants to provide the '{info.Name}' asset multiple times"; - error = $"{errorPhrase}. An asset can't be loaded multiple times, so SMAPI will use the default asset instead. Uninstall one of the mods to fix this. (Message for modders: you should avoid {nameof(AssetLoadPriority)}.{nameof(AssetLoadPriority.Exclusive)} and {nameof(IAssetLoader)} if possible to avoid conflicts.)"; + error = $"{errorPhrase}. An asset can't be loaded multiple times, so SMAPI will use the default asset instead. Uninstall one of the mods to fix this. (Message for modders: you should avoid {nameof(AssetLoadPriority)}.{nameof(AssetLoadPriority.Exclusive)}" +#if SMAPI_DEPRECATED + + " and {nameof(IAssetLoader)}" +#endif + + " if possible to avoid conflicts.)"; return false; } @@ -349,6 +361,7 @@ namespace StardewModdingAPI.Framework.ContentManagers // handle mismatch if (loadedMap.TileSheets.Count <= vanillaSheet.Index || loadedMap.TileSheets[vanillaSheet.Index].Id != vanillaSheet.Id) { +#if SMAPI_DEPRECATED // only show warning if not farm map // This is temporary: mods shouldn't do this for any vanilla map, but these are the ones we know will crash. Showing a warning for others instead gives modders time to update their mods, while still simplifying troubleshooting. bool isFarmMap = info.Name.IsEquivalentTo("Maps/Farm") || info.Name.IsEquivalentTo("Maps/Farm_Combat") || info.Name.IsEquivalentTo("Maps/Farm_Fishing") || info.Name.IsEquivalentTo("Maps/Farm_Foraging") || info.Name.IsEquivalentTo("Maps/Farm_FourCorners") || info.Name.IsEquivalentTo("Maps/Farm_Island") || info.Name.IsEquivalentTo("Maps/Farm_Mining"); @@ -361,7 +374,12 @@ namespace StardewModdingAPI.Framework.ContentManagers mod.LogAsMod($"SMAPI blocked a '{info.Name}' map load: {reason}", LogLevel.Error); return false; } + mod.LogAsMod($"SMAPI found an issue with a '{info.Name}' map load: {reason}", LogLevel.Warn); +#else + mod.LogAsMod($"SMAPI found an issue with a '{info.Name}' map load: {this.GetOnBehalfOfLabel(loader.OnBehalfOf, parenthetical: false) ?? "mod"} reordered the original tilesheets, which often causes crashes.\nTechnical details for mod author: Expected order: {string.Join(", ", vanillaTilesheetRefs.Select(p => p.Id))}. See https://stardewvalleywiki.com/Modding:Maps#Tilesheet_order for help.", LogLevel.Error); + return false; +#endif } } } diff --git a/src/SMAPI/Framework/ContentPack.cs b/src/SMAPI/Framework/ContentPack.cs index 70fe51f8..a1d977e4 100644 --- a/src/SMAPI/Framework/ContentPack.cs +++ b/src/SMAPI/Framework/ContentPack.cs @@ -96,6 +96,7 @@ namespace StardewModdingAPI.Framework } } +#if SMAPI_DEPRECATED /// [Obsolete($"Use {nameof(IContentPack.ModContent)}.{nameof(IModContentHelper.Load)} instead. This method will be removed in SMAPI 4.0.0.")] public T LoadAsset(string key) @@ -110,6 +111,7 @@ namespace StardewModdingAPI.Framework { return this.ModContent.GetInternalAssetName(key).Name; } +#endif /********* diff --git a/src/SMAPI/Framework/ModHelpers/CommandHelper.cs b/src/SMAPI/Framework/ModHelpers/CommandHelper.cs index ddbd618a..21435f62 100644 --- a/src/SMAPI/Framework/ModHelpers/CommandHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/CommandHelper.cs @@ -1,5 +1,7 @@ using System; +#if SMAPI_DEPRECATED using StardewModdingAPI.Framework.Deprecations; +#endif namespace StardewModdingAPI.Framework.ModHelpers { @@ -32,6 +34,7 @@ namespace StardewModdingAPI.Framework.ModHelpers return this; } +#if SMAPI_DEPRECATED /// [Obsolete("Use mod-provided APIs to integrate with mods instead. This method will be removed in SMAPI 4.0.0.")] public bool Trigger(string name, string[] arguments) @@ -45,5 +48,6 @@ namespace StardewModdingAPI.Framework.ModHelpers return this.CommandManager.Trigger(name, arguments); } +#endif } } diff --git a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs index 427adac2..9992cb52 100644 --- a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs @@ -1,3 +1,4 @@ +#if SMAPI_DEPRECATED using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -249,3 +250,4 @@ namespace StardewModdingAPI.Framework.ModHelpers } } } +#endif diff --git a/src/SMAPI/Framework/ModHelpers/ModHelper.cs b/src/SMAPI/Framework/ModHelpers/ModHelper.cs index 48973691..9ac3b6f7 100644 --- a/src/SMAPI/Framework/ModHelpers/ModHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ModHelper.cs @@ -1,7 +1,9 @@ using System; using System.IO; using StardewModdingAPI.Events; +#if SMAPI_DEPRECATED using StardewModdingAPI.Framework.Deprecations; +#endif using StardewModdingAPI.Framework.Input; namespace StardewModdingAPI.Framework.ModHelpers @@ -9,12 +11,14 @@ namespace StardewModdingAPI.Framework.ModHelpers /// Provides simplified APIs for writing mods. internal class ModHelper : BaseHelper, IModHelper, IDisposable { +#if SMAPI_DEPRECATED /********* ** Fields *********/ /// The backing field for . [Obsolete("This only exists to support legacy code and will be removed in SMAPI 4.0.0.")] private readonly ContentHelper ContentImpl; +#endif /********* @@ -26,6 +30,7 @@ namespace StardewModdingAPI.Framework.ModHelpers /// public IModEvents Events { get; } +#if SMAPI_DEPRECATED /// [Obsolete($"Use {nameof(IGameContentHelper)} or {nameof(IModContentHelper)} instead.")] public IContentHelper Content @@ -42,6 +47,7 @@ namespace StardewModdingAPI.Framework.ModHelpers return this.ContentImpl; } } +#endif /// public IGameContentHelper GameContent { get; } @@ -82,7 +88,6 @@ namespace StardewModdingAPI.Framework.ModHelpers /// The full path to the mod's folder. /// Manages the game's input state for the current player instance. That may not be the main player in split-screen mode. /// Manages access to events raised by SMAPI. - /// An API for loading content assets. /// An API for loading content assets from the game's Content folder or via . /// An API for loading content assets from your mod's files. /// An API for managing content packs. @@ -96,9 +101,9 @@ namespace StardewModdingAPI.Framework.ModHelpers /// The path does not exist on disk. public ModHelper( IModMetadata mod, string modDirectory, Func currentInputState, IModEvents events, -#pragma warning disable CS0612 // deprecated code +#if SMAPI_DEPRECATED ContentHelper contentHelper, -#pragma warning restore CS0612 +#endif IGameContentHelper gameContentHelper, IModContentHelper modContentHelper, IContentPackHelper contentPackHelper, ICommandHelper commandHelper, IDataHelper dataHelper, IModRegistry modRegistry, IReflectionHelper reflectionHelper, IMultiplayerHelper multiplayer, ITranslationHelper translationHelper ) : base(mod) @@ -111,9 +116,9 @@ namespace StardewModdingAPI.Framework.ModHelpers // initialize this.DirectoryPath = modDirectory; -#pragma warning disable CS0612 // deprecated code +#if SMAPI_DEPRECATED this.ContentImpl = contentHelper ?? throw new ArgumentNullException(nameof(contentHelper)); -#pragma warning restore CS0612 +#endif this.GameContent = gameContentHelper ?? throw new ArgumentNullException(nameof(gameContentHelper)); this.ModContent = modContentHelper ?? throw new ArgumentNullException(nameof(modContentHelper)); this.ContentPacks = contentPackHelper ?? throw new ArgumentNullException(nameof(contentPackHelper)); @@ -127,12 +132,14 @@ namespace StardewModdingAPI.Framework.ModHelpers this.Events = events; } +#if SMAPI_DEPRECATED /// Get the underlying instance for . [Obsolete("This only exists to support legacy code and will be removed in SMAPI 4.0.0.")] public ContentHelper GetLegacyContentHelper() { return this.ContentImpl; } +#endif /**** ** Mod config file diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs index e5aaa8ee..eb940c41 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs @@ -163,6 +163,7 @@ namespace StardewModdingAPI.Framework.ModLoading this.AssemblyDefinitionResolver.Add(assembly.Definition); } +#if SMAPI_DEPRECATED // special case: clear legacy-DLL warnings if the mod bundles a copy if (mod.Warnings.HasFlag(ModWarning.DetectedLegacyCachingDll)) { @@ -185,6 +186,7 @@ namespace StardewModdingAPI.Framework.ModLoading if (File.Exists(Path.Combine(mod.DirectoryPath, "System.Security.Permissions.dll"))) mod.RemoveWarning(ModWarning.DetectedLegacyPermissionsDll); } +#endif // throw if incompatibilities detected if (!assumeCompatible && mod.Warnings.HasFlag(ModWarning.BrokenCodeLoaded)) @@ -452,6 +454,7 @@ namespace StardewModdingAPI.Framework.ModLoading mod.SetWarning(ModWarning.AccessesShell); break; +#if SMAPI_DEPRECATED case InstructionHandleResult.DetectedLegacyCachingDll: template = $"{logPrefix}Detected reference to System.Runtime.Caching.dll, which will be removed in SMAPI 4.0.0."; mod.SetWarning(ModWarning.DetectedLegacyCachingDll); @@ -466,6 +469,7 @@ namespace StardewModdingAPI.Framework.ModLoading template = $"{logPrefix}Detected reference to System.Security.Permissions.dll, which will be removed in SMAPI 4.0.0."; mod.SetWarning(ModWarning.DetectedLegacyPermissionsDll); break; +#endif case InstructionHandleResult.None: break; diff --git a/src/SMAPI/Framework/ModLoading/Finders/LegacyAssemblyFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/LegacyAssemblyFinder.cs index d3437b05..77380907 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/LegacyAssemblyFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/LegacyAssemblyFinder.cs @@ -1,3 +1,4 @@ +#if SMAPI_DEPRECATED using Mono.Cecil; using StardewModdingAPI.Framework.ModLoading.Framework; @@ -47,3 +48,4 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders } } } +#endif diff --git a/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs b/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs index 476c30d0..189ca64e 100644 --- a/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs +++ b/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs @@ -32,6 +32,7 @@ namespace StardewModdingAPI.Framework.ModLoading /// The instruction accesses the OS shell or processes directly. DetectedShellAccess, +#if SMAPI_DEPRECATED /// The module references the legacy System.Configuration.ConfigurationManager assembly and doesn't include a copy in the mod folder, so it'll break in SMAPI 4.0.0. DetectedLegacyConfigurationDll, @@ -40,5 +41,6 @@ namespace StardewModdingAPI.Framework.ModLoading /// The module references the legacy System.Security.Permissions assembly and doesn't include a copy in the mod folder, so it'll break in SMAPI 4.0.0. DetectedLegacyPermissionsDll +#endif } } diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 385a94ea..ff3eadf5 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -32,7 +32,9 @@ using StardewModdingAPI.Framework.Networking; using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Framework.Rendering; using StardewModdingAPI.Framework.Serialization; +#if SMAPI_DEPRECATED using StardewModdingAPI.Framework.StateTracking.Comparers; +#endif using StardewModdingAPI.Framework.StateTracking.Snapshots; using StardewModdingAPI.Framework.Utilities; using StardewModdingAPI.Internal; @@ -139,8 +141,10 @@ namespace StardewModdingAPI.Framework /// The maximum number of consecutive attempts SMAPI should make to recover from an update error. private readonly Countdown UpdateCrashTimer = new(60); // 60 ticks = roughly one second +#if SMAPI_DEPRECATED /// Asset interceptors added or removed since the last tick. private readonly List ReloadAssetInterceptorsQueue = new(); +#endif /// A list of queued commands to parse and execute. /// This property must be thread-safe, since it's accessed from a separate console input thread. @@ -483,6 +487,7 @@ namespace StardewModdingAPI.Framework return; } +#if SMAPI_DEPRECATED /********* ** Reload assets when interceptors are added/removed *********/ @@ -515,6 +520,7 @@ namespace StardewModdingAPI.Framework // reload affected assets this.ContentCore.InvalidateCache(asset => interceptors.Any(p => p.CanIntercept(asset))); } +#endif /********* ** Parse commands @@ -1646,9 +1652,9 @@ namespace StardewModdingAPI.Framework // initialize loaded non-content-pack mods this.Monitor.Log("Launching mods...", LogLevel.Debug); -#pragma warning disable CS0612, CS0618 // deprecated code foreach (IModMetadata metadata in loadedMods) { +#if SMAPI_DEPRECATED // add interceptors if (metadata.Mod?.Helper is ModHelper helper) { @@ -1684,7 +1690,6 @@ namespace StardewModdingAPI.Framework content.ObservableAssetEditors.CollectionChanged += (_, e) => this.OnAssetInterceptorsChanged(metadata, e.NewItems?.Cast(), e.OldItems?.Cast(), this.ContentCore.Editors); content.ObservableAssetLoaders.CollectionChanged += (_, e) => this.OnAssetInterceptorsChanged(metadata, e.NewItems?.Cast(), e.OldItems?.Cast(), this.ContentCore.Loaders); } -#pragma warning restore CS0612, CS0618 // log deprecation warnings if (metadata.HasWarnings(ModWarning.DetectedLegacyCachingDll, ModWarning.DetectedLegacyConfigurationDll, ModWarning.DetectedLegacyPermissionsDll)) @@ -1710,6 +1715,7 @@ namespace StardewModdingAPI.Framework ); } } +#endif // call entry method Context.HeuristicModsRunningCode.Push(metadata); @@ -1750,6 +1756,7 @@ namespace StardewModdingAPI.Framework this.Monitor.Log("Mods loaded and ready!", LogLevel.Debug); } +#if SMAPI_DEPRECATED /// Raised after a mod adds or removes asset interceptors. /// The asset interceptor type (one of or ). /// The mod metadata. @@ -1772,6 +1779,7 @@ namespace StardewModdingAPI.Framework list.Remove(entry); } } +#endif /// Load a given mod. /// The mod to load. @@ -1915,9 +1923,9 @@ namespace StardewModdingAPI.Framework { IModEvents events = new ModEvents(mod, this.EventManager); ICommandHelper commandHelper = new CommandHelper(mod, this.CommandManager); -#pragma warning disable CS0612 // deprecated code +#if SMAPI_DEPRECATED ContentHelper contentHelper = new(contentCore, mod.DirectoryPath, mod, monitor, this.Reflection); -#pragma warning restore CS0612 +#endif GameContentHelper gameContentHelper = new(contentCore, mod, mod.DisplayName, monitor, this.Reflection); IModContentHelper modContentHelper = new ModContentHelper(contentCore, mod.DirectoryPath, mod, mod.DisplayName, gameContentHelper.GetUnderlyingContentManager(), this.Reflection); IContentPackHelper contentPackHelper = new ContentPackHelper( @@ -1930,7 +1938,11 @@ namespace StardewModdingAPI.Framework IModRegistry modRegistryHelper = new ModRegistryHelper(mod, this.ModRegistry, proxyFactory, monitor); IMultiplayerHelper multiplayerHelper = new MultiplayerHelper(mod, this.Multiplayer); - modHelper = new ModHelper(mod, mod.DirectoryPath, () => this.GetCurrentGameInstance().Input, events, contentHelper, gameContentHelper, modContentHelper, contentPackHelper, commandHelper, dataHelper, modRegistryHelper, reflectionHelper, multiplayerHelper, translationHelper); + modHelper = new ModHelper(mod, mod.DirectoryPath, () => this.GetCurrentGameInstance().Input, events, +#if SMAPI_DEPRECATED + contentHelper, +#endif + gameContentHelper, modContentHelper, contentPackHelper, commandHelper, dataHelper, modRegistryHelper, reflectionHelper, multiplayerHelper, translationHelper); } // init mod -- cgit From be086cf0056294bc5643bde3bb5b7b73aa4b362f Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 22 Jun 2022 01:53:37 -0400 Subject: avoid unneeded overhead of ConcurrentQueue --- src/SMAPI/Framework/CommandQueue.cs | 47 +++++++++++++++++++++++++++++++++++++ src/SMAPI/Framework/SCore.cs | 43 ++++++++++++++++----------------- 2 files changed, 69 insertions(+), 21 deletions(-) create mode 100644 src/SMAPI/Framework/CommandQueue.cs (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/CommandQueue.cs b/src/SMAPI/Framework/CommandQueue.cs new file mode 100644 index 00000000..c51016ad --- /dev/null +++ b/src/SMAPI/Framework/CommandQueue.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +namespace StardewModdingAPI.Framework +{ + /// A thread-safe command queue optimized for infrequent changes. + internal class CommandQueue + { + /******** + ** Fields + ********/ + /// The underlying list of queued commands to parse and execute. + private readonly List RawCommandQueue = new(); + + + /******** + ** Public methods + ********/ + /// Add a command to the queue. + /// The command to add. + public void Add(string command) + { + lock (this.RawCommandQueue) + this.RawCommandQueue.Add(command); + } + + /// Remove and return all queued commands, if any. + /// The commands that were dequeued, in the order they were originally queued. + /// Returns whether any values were dequeued. + [SuppressMessage("ReSharper", "InconsistentlySynchronizedField", Justification = "Deliberately check if it's empty before locking unnecessarily.")] + public bool TryDequeue([NotNullWhen(true)] out string[]? queued) + { + if (this.RawCommandQueue.Count is 0) + { + queued = null; + return false; + } + + lock (this.RawCommandQueue) + { + queued = this.RawCommandQueue.ToArray(); + this.RawCommandQueue.Clear(); + return queued.Length > 0; + } + } + } +} diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index ff3eadf5..cc332225 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -147,8 +146,7 @@ namespace StardewModdingAPI.Framework #endif /// A list of queued commands to parse and execute. - /// This property must be thread-safe, since it's accessed from a separate console input thread. - private readonly ConcurrentQueue RawCommandQueue = new(); + private readonly CommandQueue RawCommandQueue = new(); /// A list of commands to execute on each screen. private readonly PerScreen> ScreenCommandQueue = new(() => new List()); @@ -437,7 +435,7 @@ namespace StardewModdingAPI.Framework () => this.LogManager.RunConsoleInputLoop( commandManager: this.CommandManager, reloadTranslations: this.ReloadTranslations, - handleInput: input => this.RawCommandQueue.Enqueue(input), + handleInput: input => this.RawCommandQueue.Add(input), continueWhile: () => this.IsGameRunning && !this.CancellationToken.IsCancellationRequested ) ).Start(); @@ -525,29 +523,32 @@ namespace StardewModdingAPI.Framework /********* ** Parse commands *********/ - while (this.RawCommandQueue.TryDequeue(out string? rawInput)) + if (this.RawCommandQueue.TryDequeue(out string[]? rawCommands)) { - // parse command - string? name; - string[]? args; - Command? command; - int screenId; - try + foreach (string rawInput in rawCommands) { - if (!this.CommandManager.TryParse(rawInput, out name, out args, out command, out screenId)) + // parse command + string? name; + string[]? args; + Command? command; + int screenId; + try + { + if (!this.CommandManager.TryParse(rawInput, out name, out args, out command, out screenId)) + { + this.Monitor.Log("Unknown command; type 'help' for a list of available commands.", LogLevel.Error); + continue; + } + } + catch (Exception ex) { - this.Monitor.Log("Unknown command; type 'help' for a list of available commands.", LogLevel.Error); + this.Monitor.Log($"Failed parsing that command:\n{ex.GetLogSummary()}", LogLevel.Error); continue; } - } - catch (Exception ex) - { - this.Monitor.Log($"Failed parsing that command:\n{ex.GetLogSummary()}", LogLevel.Error); - continue; - } - // queue command for screen - this.ScreenCommandQueue.GetValueForScreen(screenId).Add(new(command, name, args)); + // queue command for screen + this.ScreenCommandQueue.GetValueForScreen(screenId).Add(new(command, name, args)); + } } -- cgit From 525ca7c9c99272c5aff557545c285f4307526589 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 24 Jun 2022 02:06:25 -0400 Subject: fix config.user.json overrides no longer applied --- src/SMAPI/Framework/Models/SConfig.cs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/Models/SConfig.cs b/src/SMAPI/Framework/Models/SConfig.cs index baef6144..62b15405 100644 --- a/src/SMAPI/Framework/Models/SConfig.cs +++ b/src/SMAPI/Framework/Models/SConfig.cs @@ -38,45 +38,49 @@ namespace StardewModdingAPI.Framework.Models /******** ** Accessors ********/ + // + // Note: properties must be writable to support merging config.user.json into it. + // + /// Whether to enable development features. - public bool DeveloperMode { get; private set; } + public bool DeveloperMode { get; set; } /// Whether to check for newer versions of SMAPI and mods on startup. - public bool CheckForUpdates { get; } + public bool CheckForUpdates { get; set; } /// Whether to add a section to the 'mod issues' list for mods which which directly use potentially sensitive .NET APIs like file or shell access. - public bool ParanoidWarnings { get; } + public bool ParanoidWarnings { get; set; } /// Whether to show beta versions as valid updates. - public bool UseBetaChannel { get; } + public bool UseBetaChannel { get; set; } /// SMAPI's GitHub project name, used to perform update checks. - public string GitHubProjectName { get; } + public string GitHubProjectName { get; set; } /// The base URL for SMAPI's web API, used to perform update checks. - public string WebApiBaseUrl { get; } + public string WebApiBaseUrl { get; set; } /// The log contexts for which to enable verbose logging, which may show a lot more information to simplify troubleshooting. /// The possible values are "*" (everything is verbose), "SMAPI", (SMAPI itself), or mod IDs. - public HashSet VerboseLogging { get; } + public HashSet VerboseLogging { get; set; } /// Whether SMAPI should rewrite mods for compatibility. - public bool RewriteMods { get; } + public bool RewriteMods { get; set; } /// Whether to use raw image data when possible, instead of initializing an XNA Texture2D instance through the GPU. - public bool UseRawImageLoading { get; } + public bool UseRawImageLoading { get; set; } /// Whether to make SMAPI file APIs case-insensitive, even on Linux. - public bool UseCaseInsensitivePaths { get; } + public bool UseCaseInsensitivePaths { get; set; } /// Whether SMAPI should log network traffic. Best combined with , which includes network metadata. - public bool LogNetworkTraffic { get; } + public bool LogNetworkTraffic { get; set; } /// The colors to use for text written to the SMAPI console. - public ColorSchemeConfig ConsoleColors { get; } + public ColorSchemeConfig ConsoleColors { get; set; } /// The mod IDs SMAPI should ignore when performing update checks or validating update keys. - public HashSet SuppressUpdateChecks { get; } + public HashSet SuppressUpdateChecks { get; set; } /******** -- cgit From ca9efad7a7949ca87f3ccf7ec4d01332d1fad84b Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 24 Jun 2022 17:00:39 -0400 Subject: avoid cancellation token for tracking exit state This apparently causes noticeable lag for a minority of players. --- src/SMAPI/Framework/SCore.cs | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index cc332225..16c168a0 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -66,8 +66,8 @@ namespace StardewModdingAPI.Framework /**** ** Low-level components ****/ - /// Tracks whether the game should exit immediately and any pending initialization should be cancelled. - private readonly CancellationTokenSource CancellationToken = new(); + /// Whether the game should exit immediately and any pending initialization should be cancelled. + private bool IsExiting; /// Manages the SMAPI console window and log file. private readonly LogManager LogManager; @@ -272,16 +272,6 @@ namespace StardewModdingAPI.Framework new TitleMenuPatcher(this.OnLoadStageChanged) ); - // add exit handler - this.CancellationToken.Token.Register(() => - { - if (this.IsGameRunning) - { - this.LogManager.WriteCrashLog(); - this.Game.Exit(); - } - }); - // set window titles this.UpdateWindowTitles(); } @@ -358,8 +348,8 @@ namespace StardewModdingAPI.Framework // dispose core components this.IsGameRunning = false; + this.IsExiting = true; this.ContentCore?.Dispose(); - this.CancellationToken.Dispose(); this.Game?.Dispose(); this.LogManager.Dispose(); // dispose last to allow for any last-second log messages @@ -374,7 +364,7 @@ namespace StardewModdingAPI.Framework /// Initialize mods before the first game asset is loaded. At this point the core content managers are loaded (so mods can load their own assets), but the game is mostly uninitialized. private void InitializeBeforeFirstAssetLoaded() { - if (this.CancellationToken.IsCancellationRequested) + if (this.IsExiting) { this.Monitor.Log("SMAPI shutting down: aborting initialization.", LogLevel.Warn); return; @@ -436,7 +426,7 @@ namespace StardewModdingAPI.Framework commandManager: this.CommandManager, reloadTranslations: this.ReloadTranslations, handleInput: input => this.RawCommandQueue.Add(input), - continueWhile: () => this.IsGameRunning && !this.CancellationToken.IsCancellationRequested + continueWhile: () => this.IsGameRunning && !this.IsExiting ) ).Start(); } @@ -479,7 +469,7 @@ namespace StardewModdingAPI.Framework ** Special cases *********/ // Abort if SMAPI is exiting. - if (this.CancellationToken.IsCancellationRequested) + if (this.IsExiting) { this.Monitor.Log("SMAPI shutting down: aborting update."); return; @@ -2233,7 +2223,10 @@ namespace StardewModdingAPI.Framework private void ExitGameImmediately(string message) { this.Monitor.LogFatal(message); - this.CancellationToken.Cancel(); + this.LogManager.WriteCrashLog(); + + this.IsExiting = true; + this.Game.Exit(); } /// Get the screen ID that should be logged to distinguish between players in split-screen mode, if any. -- cgit From 6d11c41facb2e1397a25110517cc281f87be2caf Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 28 Jun 2022 18:17:27 -0400 Subject: migrate update checks to FluentHttpClient WebClient isn't needed for compatibility with macOS after the .NET 5 update in Stardew Valley 1.5.5, and causes noticeable lag for some players even when running on a background thread. --- src/SMAPI/Framework/SCore.cs | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 16c168a0..fdfe70fc 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -10,6 +10,7 @@ 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; @@ -406,7 +407,7 @@ namespace StardewModdingAPI.Framework this.CheckForSoftwareConflicts(); // check for updates - this.CheckForUpdatesAsync(mods); + _ = this.CheckForUpdatesAsync(mods); // ignore task since the main thread doesn't need to wait for it } // update window titles @@ -1450,16 +1451,15 @@ namespace StardewModdingAPI.Framework /// Asynchronously check for a new version of SMAPI and any installed mods, and print alerts to the console if an update is available. /// The mods to include in the update check (if eligible). - private void CheckForUpdatesAsync(IModMetadata[] mods) + private async Task CheckForUpdatesAsync(IModMetadata[] mods) { - if (!this.Settings.CheckForUpdates) - return; - - new Thread(() => + try { + if (!this.Settings.CheckForUpdates) + return; + // create client - string url = this.Settings.WebApiBaseUrl; - WebApiClient client = new(url, Constants.ApiVersion); + using WebApiClient client = new(this.Settings.WebApiBaseUrl, Constants.ApiVersion); this.Monitor.Log("Checking for updates..."); // check SMAPI version @@ -1469,9 +1469,15 @@ namespace StardewModdingAPI.Framework try { // fetch update check - ModEntryModel response = client.GetModInfo(new[] { new ModSearchEntryModel("Pathoschild.SMAPI", Constants.ApiVersion, new[] { $"GitHub:{this.Settings.GitHubProjectName}" }) }, apiVersion: Constants.ApiVersion, gameVersion: Constants.GameVersion, platform: Constants.Platform).Single().Value; - updateFound = response.SuggestedUpdate?.Version; - updateUrl = response.SuggestedUpdate?.Url; + IDictionary response = await client.GetModInfoAsync( + mods: new[] { new ModSearchEntryModel("Pathoschild.SMAPI", Constants.ApiVersion, new[] { $"GitHub:{this.Settings.GitHubProjectName}" }) }, + apiVersion: Constants.ApiVersion, + gameVersion: Constants.GameVersion, + platform: Constants.Platform + ); + ModEntryModel updateInfo = response.Single().Value; + updateFound = updateInfo.SuggestedUpdate?.Version; + updateUrl = updateInfo.SuggestedUpdate?.Url; // log message if (updateFound != null) @@ -1480,10 +1486,10 @@ namespace StardewModdingAPI.Framework this.Monitor.Log(" SMAPI okay."); // show errors - if (response.Errors.Any()) + if (updateInfo.Errors.Any()) { this.Monitor.Log("Couldn't check for a new version of SMAPI. This won't affect your game, but you may not be notified of new versions if this keeps happening.", LogLevel.Warn); - this.Monitor.Log($"Error: {string.Join("\n", response.Errors)}"); + this.Monitor.Log($"Error: {string.Join("\n", updateInfo.Errors)}"); } } catch (Exception ex) @@ -1523,7 +1529,7 @@ namespace StardewModdingAPI.Framework // fetch results this.Monitor.Log($" Checking for updates to {searchMods.Count} mods..."); - IDictionary results = client.GetModInfo(searchMods.ToArray(), apiVersion: Constants.ApiVersion, gameVersion: Constants.GameVersion, platform: Constants.Platform); + IDictionary results = await client.GetModInfoAsync(searchMods.ToArray(), apiVersion: Constants.ApiVersion, gameVersion: Constants.GameVersion, platform: Constants.Platform); // extract update alerts & errors var updates = new List>(); @@ -1573,7 +1579,15 @@ namespace StardewModdingAPI.Framework ); } } - }).Start(); + } + catch (Exception ex) + { + this.Monitor.Log("Couldn't check for updates. This won't affect your game, but you won't be notified of SMAPI or mod updates if this keeps happening.", LogLevel.Warn); + this.Monitor.Log(ex is WebException && ex.InnerException == null + ? ex.Message + : ex.ToString() + ); + } } /// Create a directory path if it doesn't exist. -- cgit From d717e246b67bd1b019dab26562be1dfdc8edc73a Mon Sep 17 00:00:00 2001 From: Ishan Jalan <44338423+strobel1ght@users.noreply.github.com> Date: Sat, 2 Jul 2022 08:42:35 +0530 Subject: Current version in mod check Added "(You have x.x.x)" to the mod update check. --- src/SMAPI/Framework/SCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index fdfe70fc..283755d6 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -1565,7 +1565,7 @@ namespace StardewModdingAPI.Framework this.Monitor.Newline(); this.Monitor.Log($"You can update {updates.Count} mod{(updates.Count != 1 ? "s" : "")}:", LogLevel.Alert); foreach ((IModMetadata mod, ISemanticVersion newVersion, string newUrl) in updates) - this.Monitor.Log($" {mod.DisplayName} {newVersion}: {newUrl}", LogLevel.Alert); + this.Monitor.Log($" {mod.DisplayName} {newVersion}: {newUrl} (You have {mod.Manifest.Version}", LogLevel.Alert); } else this.Monitor.Log(" All mods up to date."); -- cgit From f3a4b316b7294fea897514a08c45bc9d926a00c6 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 5 Jul 2022 19:01:28 -0400 Subject: fix PyTK compatibility mode not handling some edge cases --- .../Framework/ContentManagers/ModContentManager.cs | 27 +++++----------------- 1 file changed, 6 insertions(+), 21 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs index 8c5d0f84..f3cf05d9 100644 --- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; @@ -47,9 +46,6 @@ namespace StardewModdingAPI.Framework.ContentManagers /// If a map tilesheet's image source has no file extensions, the file extensions to check for in the local mod folder. private static readonly string[] LocalTilesheetExtensions = { ".png", ".xnb" }; - /// A lookup of image file paths to whether they have PyTK scaling information. - private static readonly Dictionary IsPyTkScaled = new(StringComparer.OrdinalIgnoreCase); - /********* ** Accessors @@ -211,24 +207,13 @@ namespace StardewModdingAPI.Framework.ContentManagers { if (ModContentManager.EnablePyTkLegacyMode) { - if (!ModContentManager.IsPyTkScaled.TryGetValue(file.FullName, out bool isScaled)) - { - string? dirPath = file.DirectoryName; - string fileName = $"{Path.GetFileNameWithoutExtension(file.Name)}.pytk.json"; - - string path = dirPath is not null - ? Path.Combine(dirPath, fileName) - : fileName; - - ModContentManager.IsPyTkScaled[file.FullName] = isScaled = File.Exists(path); - } - - asRawData = !isScaled; - if (!asRawData) - this.Monitor.LogOnce("Enabled compatibility mode for PyTK scaled textures. This won't cause any issues, but may impact performance.", LogLevel.Warn); + // PyTK intercepts Texture2D file loads to rescale them (e.g. for HD portraits), + // but doesn't support IRawTextureData loads yet. We can't just check if the + // current file has a '.pytk.json' rescale file though, since PyTK may still + // rescale it if the original asset or another edit gets rescaled. + asRawData = false; + this.Monitor.LogOnce("Enabled compatibility mode for PyTK 1.23.0 or earlier. This won't cause any issues, but may impact performance.", LogLevel.Warn); } - else - asRawData = true; } // load -- cgit From 543e45f9bde5929ca3c12db23f7d5b2ae0c653cd Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 5 Jul 2022 23:21:51 -0400 Subject: remove artifacts, tweak text --- src/SMAPI/Framework/SCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 283755d6..d0effb03 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -1565,7 +1565,7 @@ namespace StardewModdingAPI.Framework this.Monitor.Newline(); this.Monitor.Log($"You can update {updates.Count} mod{(updates.Count != 1 ? "s" : "")}:", LogLevel.Alert); foreach ((IModMetadata mod, ISemanticVersion newVersion, string newUrl) in updates) - this.Monitor.Log($" {mod.DisplayName} {newVersion}: {newUrl} (You have {mod.Manifest.Version}", LogLevel.Alert); + this.Monitor.Log($" {mod.DisplayName} {newVersion}: {newUrl} (you have {mod.Manifest.Version})", LogLevel.Alert); } else this.Monitor.Log(" All mods up to date."); -- cgit From 4d9fd63d9e890a10029508c7d7e31dcc0b579db7 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 6 Jul 2022 19:24:49 -0400 Subject: update code annotations --- src/SMAPI/Framework/ContentManagers/BaseContentManager.cs | 3 +-- src/SMAPI/Framework/Logging/LogManager.cs | 2 +- src/SMAPI/Framework/ModLoading/ModMetadata.cs | 2 +- src/SMAPI/Framework/ModLoading/ModResolver.cs | 4 ++-- .../Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs | 2 +- src/SMAPI/Framework/ModLoading/RewriteFacades/SpriteBatchFacade.cs | 1 - src/SMAPI/Framework/Networking/MultiplayerPeerMod.cs | 2 +- src/SMAPI/Framework/Rendering/SXnaDisplayDevice.cs | 2 +- src/SMAPI/Framework/SCore.cs | 6 +++--- src/SMAPI/Framework/SGame.cs | 3 +++ 10 files changed, 14 insertions(+), 13 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs index d7be0c37..54f8e2a2 100644 --- a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs @@ -111,7 +111,6 @@ namespace StardewModdingAPI.Framework.ContentManagers } /// - [SuppressMessage("ReSharper", "ConditionIsAlwaysTrueOrFalse", Justification = "Copied as-is from game code")] public sealed override string LoadBaseString(string path) { try @@ -119,7 +118,7 @@ namespace StardewModdingAPI.Framework.ContentManagers // copied as-is from LocalizedContentManager.LoadBaseString // This is only changed to call this.Load instead of base.Load, to support mod assets this.ParseStringPath(path, out string assetName, out string key); - Dictionary strings = this.Load>(assetName, LanguageCode.en); + Dictionary? strings = this.Load?>(assetName, LanguageCode.en); return strings != null && strings.ContainsKey(key) ? this.GetString(strings, key) : path; diff --git a/src/SMAPI/Framework/Logging/LogManager.cs b/src/SMAPI/Framework/Logging/LogManager.cs index d811ed5c..c0b7c0ba 100644 --- a/src/SMAPI/Framework/Logging/LogManager.cs +++ b/src/SMAPI/Framework/Logging/LogManager.cs @@ -400,7 +400,7 @@ namespace StardewModdingAPI.Framework.Logging /// The loaded mods. /// The mods which could not be loaded. /// Whether to log issues for mods which directly use potentially sensitive .NET APIs like file or shell access. - [SuppressMessage("ReSharper", "ConstantConditionalAccessQualifier", Justification = "Manifests aren't guaranteed non-null at this point in the loading process.")] + [SuppressMessage("ReSharper", "ConditionalAccessQualifierIsNonNullableAccordingToAPIContract", Justification = "Manifests aren't guaranteed non-null at this point in the loading process.")] private void LogModWarnings(IEnumerable mods, IModMetadata[] skippedMods, bool logParanoidWarnings) { // get mods with warnings diff --git a/src/SMAPI/Framework/ModLoading/ModMetadata.cs b/src/SMAPI/Framework/ModLoading/ModMetadata.cs index aa4d2d8c..ac7a6bbd 100644 --- a/src/SMAPI/Framework/ModLoading/ModMetadata.cs +++ b/src/SMAPI/Framework/ModLoading/ModMetadata.cs @@ -83,7 +83,7 @@ namespace StardewModdingAPI.Framework.ModLoading /// [MemberNotNullWhen(true, nameof(ModMetadata.ContentPack))] - [SuppressMessage("ReSharper", "ConstantConditionalAccessQualifier", Justification = "The manifest may be null for broken mods while loading.")] + [SuppressMessage("ReSharper", "ConditionalAccessQualifierIsNonNullableAccordingToAPIContract", Justification = "The manifest may be null for broken mods while loading.")] public bool IsContentPack => this.Manifest?.ContentPackFor != null; /// The fake content packs created by this mod, if any. diff --git a/src/SMAPI/Framework/ModLoading/ModResolver.cs b/src/SMAPI/Framework/ModLoading/ModResolver.cs index 3e7144f9..abc46d47 100644 --- a/src/SMAPI/Framework/ModLoading/ModResolver.cs +++ b/src/SMAPI/Framework/ModLoading/ModResolver.cs @@ -60,8 +60,8 @@ namespace StardewModdingAPI.Framework.ModLoading /// Get an update URL for an update key (if valid). /// Get a file lookup for the given directory. /// Whether to validate that files referenced in the manifest (like ) exist on disk. This can be disabled to only validate the manifest itself. - [SuppressMessage("ReSharper", "ConstantConditionalAccessQualifier", Justification = "Manifest values may be null before they're validated.")] - [SuppressMessage("ReSharper", "ConditionIsAlwaysTrueOrFalse", Justification = "Manifest values may be null before they're validated.")] + [SuppressMessage("ReSharper", "ConditionalAccessQualifierIsNonNullableAccordingToAPIContract", Justification = "Manifest values may be null before they're validated.")] + [SuppressMessage("ReSharper", "ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract", Justification = "Manifest values may be null before they're validated.")] public void ValidateManifests(IEnumerable mods, ISemanticVersion apiVersion, Func getUpdateUrl, Func getFileLookup, bool validateFilesExist = true) { mods = mods.ToArray(); diff --git a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs index 9c8ba2b0..be45272e 100644 --- a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs +++ b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs @@ -28,7 +28,7 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades return new Harmony(id); } - [SuppressMessage("ReSharper", "ConditionIsAlwaysTrueOrFalse", Justification = "If the user passes a null original method, we let it fail in the underlying Harmony instance instead of handling it here.")] + [SuppressMessage("ReSharper", "ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract", Justification = "If the user passes a null original method, we let it fail in the underlying Harmony instance instead of handling it here.")] public DynamicMethod Patch(MethodBase original, HarmonyMethod? prefix = null, HarmonyMethod? postfix = null, HarmonyMethod? transpiler = null) { // In Harmony 1.x you could target a virtual method that's not implemented by the diff --git a/src/SMAPI/Framework/ModLoading/RewriteFacades/SpriteBatchFacade.cs b/src/SMAPI/Framework/ModLoading/RewriteFacades/SpriteBatchFacade.cs index 67569424..3eb31df3 100644 --- a/src/SMAPI/Framework/ModLoading/RewriteFacades/SpriteBatchFacade.cs +++ b/src/SMAPI/Framework/ModLoading/RewriteFacades/SpriteBatchFacade.cs @@ -10,7 +10,6 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades /// Provides method signatures that can be injected into mod code for compatibility with mods written for XNA Framework before Stardew Valley 1.5.5. /// This is public to support SMAPI rewriting and should not be referenced directly by mods. [SuppressMessage("ReSharper", "UnusedMember.Global", Justification = "Used via assembly rewriting")] - [SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Linux/macOS.")] [SuppressMessage("ReSharper", "CS1591", Justification = "Documentation not needed for facade classes.")] public class SpriteBatchFacade : SpriteBatch { diff --git a/src/SMAPI/Framework/Networking/MultiplayerPeerMod.cs b/src/SMAPI/Framework/Networking/MultiplayerPeerMod.cs index 1e150508..cc936489 100644 --- a/src/SMAPI/Framework/Networking/MultiplayerPeerMod.cs +++ b/src/SMAPI/Framework/Networking/MultiplayerPeerMod.cs @@ -22,7 +22,7 @@ namespace StardewModdingAPI.Framework.Networking *********/ /// Construct an instance. /// The mod metadata. - [SuppressMessage("ReSharper", "ConstantConditionalAccessQualifier", Justification = "The ID shouldn't be null, but we should handle it to avoid an error just in case.")] + [SuppressMessage("ReSh