summaryrefslogtreecommitdiff
path: root/src/SMAPI
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI')
-rw-r--r--src/SMAPI/Constants.cs20
-rw-r--r--src/SMAPI/Context.cs14
-rw-r--r--src/SMAPI/Events/AssetReadyEventArgs.cs2
-rw-r--r--src/SMAPI/Events/AssetRequestedEventArgs.cs4
-rw-r--r--src/SMAPI/Events/AssetsInvalidatedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/BuildingListChangedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/ButtonPressedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/ButtonReleasedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/ButtonsChangedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/ChestInventoryChangedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/CursorMovedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/DebrisListChangedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/FurnitureListChangedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/IContentEvents.cs2
-rw-r--r--src/SMAPI/Events/IDisplayEvents.cs2
-rw-r--r--src/SMAPI/Events/IGameLoopEvents.cs2
-rw-r--r--src/SMAPI/Events/IInputEvents.cs2
-rw-r--r--src/SMAPI/Events/IModEvents.cs2
-rw-r--r--src/SMAPI/Events/IMultiplayerEvents.cs2
-rw-r--r--src/SMAPI/Events/IPlayerEvents.cs2
-rw-r--r--src/SMAPI/Events/ISpecialisedEvents.cs2
-rw-r--r--src/SMAPI/Events/IWorldEvents.cs2
-rw-r--r--src/SMAPI/Events/InventoryChangedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/ItemStackSizeChange.cs2
-rw-r--r--src/SMAPI/Events/LargeTerrainFeatureListChangedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/LevelChangedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/LocaleChangedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/LocationListChangedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/MenuChangedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/ModMessageReceivedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/NpcListChangedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/ObjectListChangedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/PeerConnectedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/PeerContextReceivedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/PeerDisconnectedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/RenderedActiveMenuEventArgs.cs2
-rw-r--r--src/SMAPI/Events/RenderedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/RenderedHudEventArgs.cs2
-rw-r--r--src/SMAPI/Events/RenderedWorldEventArgs.cs2
-rw-r--r--src/SMAPI/Events/RenderingActiveMenuEventArgs.cs2
-rw-r--r--src/SMAPI/Events/RenderingEventArgs.cs2
-rw-r--r--src/SMAPI/Events/RenderingHudEventArgs.cs2
-rw-r--r--src/SMAPI/Events/RenderingWorldEventArgs.cs2
-rw-r--r--src/SMAPI/Events/TerrainFeatureListChangedEventArgs.cs2
-rw-r--r--src/SMAPI/Events/WarpedEventArgs.cs2
-rw-r--r--src/SMAPI/Framework/Command.cs2
-rw-r--r--src/SMAPI/Framework/CommandManager.cs6
-rw-r--r--src/SMAPI/Framework/Commands/HarmonySummaryCommand.cs4
-rw-r--r--src/SMAPI/Framework/Commands/HelpCommand.cs2
-rw-r--r--src/SMAPI/Framework/Commands/IInternalCommand.cs2
-rw-r--r--src/SMAPI/Framework/Commands/ReloadI18nCommand.cs2
-rw-r--r--src/SMAPI/Framework/Content/AssetData.cs2
-rw-r--r--src/SMAPI/Framework/Content/AssetDataForDictionary.cs2
-rw-r--r--src/SMAPI/Framework/Content/AssetDataForImage.cs2
-rw-r--r--src/SMAPI/Framework/Content/AssetDataForMap.cs8
-rw-r--r--src/SMAPI/Framework/Content/AssetDataForObject.cs6
-rw-r--r--src/SMAPI/Framework/Content/AssetEditOperation.cs2
-rw-r--r--src/SMAPI/Framework/Content/AssetInfo.cs2
-rw-r--r--src/SMAPI/Framework/Content/AssetInterceptorChange.cs4
-rw-r--r--src/SMAPI/Framework/Content/AssetLoadOperation.cs2
-rw-r--r--src/SMAPI/Framework/Content/AssetName.cs4
-rw-r--r--src/SMAPI/Framework/Content/AssetOperationGroup.cs2
-rw-r--r--src/SMAPI/Framework/Content/ContentCache.cs2
-rw-r--r--src/SMAPI/Framework/Content/TilesheetReference.cs3
-rw-r--r--src/SMAPI/Framework/ContentCoordinator.cs69
-rw-r--r--src/SMAPI/Framework/ContentManagers/BaseContentManager.cs10
-rw-r--r--src/SMAPI/Framework/ContentManagers/GameContentManager.cs4
-rw-r--r--src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs2
-rw-r--r--src/SMAPI/Framework/ContentManagers/IContentManager.cs3
-rw-r--r--src/SMAPI/Framework/ContentManagers/ModContentManager.cs211
-rw-r--r--src/SMAPI/Framework/ContentPack.cs40
-rw-r--r--src/SMAPI/Framework/CursorPosition.cs2
-rw-r--r--src/SMAPI/Framework/DeprecationManager.cs4
-rw-r--r--src/SMAPI/Framework/DeprecationWarning.cs2
-rw-r--r--src/SMAPI/Framework/Events/EventManager.cs2
-rw-r--r--src/SMAPI/Framework/Events/IManagedEvent.cs2
-rw-r--r--src/SMAPI/Framework/Events/ManagedEvent.cs4
-rw-r--r--src/SMAPI/Framework/Events/ManagedEventHandler.cs4
-rw-r--r--src/SMAPI/Framework/Events/ModContentEvents.cs2
-rw-r--r--src/SMAPI/Framework/Events/ModDisplayEvents.cs2
-rw-r--r--src/SMAPI/Framework/Events/ModEvents.cs2
-rw-r--r--src/SMAPI/Framework/Events/ModEventsBase.cs2
-rw-r--r--src/SMAPI/Framework/Events/ModGameLoopEvents.cs2
-rw-r--r--src/SMAPI/Framework/Events/ModInputEvents.cs2
-rw-r--r--src/SMAPI/Framework/Events/ModMultiplayerEvents.cs2
-rw-r--r--src/SMAPI/Framework/Events/ModPlayerEvents.cs2
-rw-r--r--src/SMAPI/Framework/Events/ModSpecialisedEvents.cs2
-rw-r--r--src/SMAPI/Framework/Events/ModWorldEvents.cs2
-rw-r--r--src/SMAPI/Framework/Exceptions/SAssemblyLoadFailedException.cs2
-rw-r--r--src/SMAPI/Framework/Exceptions/SContentLoadException.cs4
-rw-r--r--src/SMAPI/Framework/GameVersion.cs2
-rw-r--r--src/SMAPI/Framework/IModMetadata.cs2
-rw-r--r--src/SMAPI/Framework/Input/GamePadStateBuilder.cs2
-rw-r--r--src/SMAPI/Framework/Input/IInputStateBuilder.cs2
-rw-r--r--src/SMAPI/Framework/Input/KeyboardStateBuilder.cs4
-rw-r--r--src/SMAPI/Framework/Input/MouseStateBuilder.cs2
-rw-r--r--src/SMAPI/Framework/Input/SInputState.cs16
-rw-r--r--src/SMAPI/Framework/InternalExtensions.cs3
-rw-r--r--src/SMAPI/Framework/Logging/InterceptingTextWriter.cs2
-rw-r--r--src/SMAPI/Framework/Logging/LogFileManager.cs2
-rw-r--r--src/SMAPI/Framework/Logging/LogManager.cs2
-rw-r--r--src/SMAPI/Framework/ModHelpers/BaseHelper.cs2
-rw-r--r--src/SMAPI/Framework/ModHelpers/CommandHelper.cs2
-rw-r--r--src/SMAPI/Framework/ModHelpers/ContentHelper.cs16
-rw-r--r--src/SMAPI/Framework/ModHelpers/ContentPackHelper.cs2
-rw-r--r--src/SMAPI/Framework/ModHelpers/DataHelper.cs2
-rw-r--r--src/SMAPI/Framework/ModHelpers/GameContentHelper.cs10
-rw-r--r--src/SMAPI/Framework/ModHelpers/InputHelper.cs2
-rw-r--r--src/SMAPI/Framework/ModHelpers/ModContentHelper.cs22
-rw-r--r--src/SMAPI/Framework/ModHelpers/ModHelper.cs21
-rw-r--r--src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs4
-rw-r--r--src/SMAPI/Framework/ModHelpers/MultiplayerHelper.cs2
-rw-r--r--src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs2
-rw-r--r--src/SMAPI/Framework/ModHelpers/TranslationHelper.cs2
-rw-r--r--src/SMAPI/Framework/ModLinked.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/AssemblyLoadStatus.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/AssemblyLoader.cs22
-rw-r--r--src/SMAPI/Framework/ModLoading/AssemblyParseResult.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/MethodFinder.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/PropertyFinder.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/TypeAssemblyFinder.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/IInstructionHandler.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/IncompatibleInstructionException.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/InvalidModStateException.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/ModMetadata.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/ModResolver.cs13
-rw-r--r--src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/RewriteFacades/AccessToolsFacade.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyMethodFacade.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/RewriteFacades/SpriteBatchFacade.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs4
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs4
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Symbols/SymbolReader.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Symbols/SymbolReaderProvider.cs4
-rw-r--r--src/SMAPI/Framework/ModLoading/Symbols/SymbolWriterProvider.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs2
-rw-r--r--src/SMAPI/Framework/ModRegistry.cs8
-rw-r--r--src/SMAPI/Framework/Models/SConfig.cs7
-rw-r--r--src/SMAPI/Framework/Monitor.cs4
-rw-r--r--src/SMAPI/Framework/Networking/ModMessageModel.cs2
-rw-r--r--src/SMAPI/Framework/Networking/MultiplayerPeer.cs2
-rw-r--r--src/SMAPI/Framework/Networking/MultiplayerPeerMod.cs2
-rw-r--r--src/SMAPI/Framework/Networking/RemoteContextModModel.cs2
-rw-r--r--src/SMAPI/Framework/Networking/RemoteContextModel.cs2
-rw-r--r--src/SMAPI/Framework/Networking/SGalaxyNetClient.cs2
-rw-r--r--src/SMAPI/Framework/Networking/SGalaxyNetServer.cs8
-rw-r--r--src/SMAPI/Framework/Networking/SLidgrenClient.cs2
-rw-r--r--src/SMAPI/Framework/Networking/SLidgrenServer.cs6
-rw-r--r--src/SMAPI/Framework/Reflection/CacheEntry.cs2
-rw-r--r--src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs2
-rw-r--r--src/SMAPI/Framework/Reflection/ReflectedField.cs2
-rw-r--r--src/SMAPI/Framework/Reflection/ReflectedMethod.cs2
-rw-r--r--src/SMAPI/Framework/Reflection/ReflectedProperty.cs2
-rw-r--r--src/SMAPI/Framework/Reflection/Reflector.cs6
-rw-r--r--src/SMAPI/Framework/Rendering/SDisplayDevice.cs2
-rw-r--r--src/SMAPI/Framework/Rendering/SXnaDisplayDevice.cs2
-rw-r--r--src/SMAPI/Framework/RequestExitDelegate.cs2
-rw-r--r--src/SMAPI/Framework/SChatBox.cs2
-rw-r--r--src/SMAPI/Framework/SCore.cs81
-rw-r--r--src/SMAPI/Framework/SGame.cs10
-rw-r--r--src/SMAPI/Framework/SGameRunner.cs4
-rw-r--r--src/SMAPI/Framework/SModHooks.cs2
-rw-r--r--src/SMAPI/Framework/SMultiplayer.cs58
-rw-r--r--src/SMAPI/Framework/Serialization/KeybindConverter.cs6
-rw-r--r--src/SMAPI/Framework/Singleton.cs4
-rw-r--r--src/SMAPI/Framework/SnapshotDiff.cs2
-rw-r--r--src/SMAPI/Framework/SnapshotItemListDiff.cs2
-rw-r--r--src/SMAPI/Framework/SnapshotListDiff.cs6
-rw-r--r--src/SMAPI/Framework/StateTracking/ChestTracker.cs6
-rw-r--r--src/SMAPI/Framework/StateTracking/Comparers/EquatableComparer.cs2
-rw-r--r--src/SMAPI/Framework/StateTracking/Comparers/GenericEqualsComparer.cs2
-rw-r--r--src/SMAPI/Framework/StateTracking/Comparers/ObjectReferenceComparer.cs2
-rw-r--r--src/SMAPI/Framework/StateTracking/FieldWatchers/BaseDisposableWatcher.cs2
-rw-r--r--src/SMAPI/Framework/StateTracking/FieldWatchers/ComparableListWatcher.cs6
-rw-r--r--src/SMAPI/Framework/StateTracking/FieldWatchers/ComparableWatcher.cs2
-rw-r--r--src/SMAPI/Framework/StateTracking/FieldWatchers/ImmutableCollectionWatcher.cs4
-rw-r--r--src/SMAPI/Framework/StateTracking/FieldWatchers/NetCollectionWatcher.cs6
-rw-r--r--src/SMAPI/Framework/StateTracking/FieldWatchers/NetDictionaryWatcher.cs2
-rw-r--r--src/SMAPI/Framework/StateTracking/FieldWatchers/NetListWatcher.cs2
-rw-r--r--src/SMAPI/Framework/StateTracking/FieldWatchers/NetValueWatcher.cs2
-rw-r--r--src/SMAPI/Framework/StateTracking/FieldWatchers/ObservableCollectionWatcher.cs8
-rw-r--r--src/SMAPI/Framework/StateTracking/FieldWatchers/WatcherFactory.cs2
-rw-r--r--src/SMAPI/Framework/StateTracking/ICollectionWatcher.cs2
-rw-r--r--src/SMAPI/Framework/StateTracking/IDictionaryWatcher.cs2
-rw-r--r--src/SMAPI/Framework/StateTracking/IValueWatcher.cs2
-rw-r--r--src/SMAPI/Framework/StateTracking/IWatcher.cs2
-rw-r--r--src/SMAPI/Framework/StateTracking/LocationTracker.cs4
-rw-r--r--src/SMAPI/Framework/StateTracking/PlayerTracker.cs4
-rw-r--r--src/SMAPI/Framework/StateTracking/Snapshots/LocationSnapshot.cs16
-rw-r--r--src/SMAPI/Framework/StateTracking/Snapshots/PlayerSnapshot.cs8
-rw-r--r--src/SMAPI/Framework/StateTracking/Snapshots/WatcherSnapshot.cs18
-rw-r--r--src/SMAPI/Framework/StateTracking/Snapshots/WorldLocationsSnapshot.cs6
-rw-r--r--src/SMAPI/Framework/StateTracking/WorldLocationsTracker.cs2
-rw-r--r--src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs8
-rw-r--r--src/SMAPI/Framework/Translator.cs2
-rw-r--r--src/SMAPI/Framework/Utilities/ContextHash.cs2
-rw-r--r--src/SMAPI/Framework/Utilities/Countdown.cs2
-rw-r--r--src/SMAPI/Framework/Utilities/TickCacheDictionary.cs9
-rw-r--r--src/SMAPI/Framework/WatcherCore.cs4
-rw-r--r--src/SMAPI/GamePlatform.cs2
-rw-r--r--src/SMAPI/IAssetData.cs2
-rw-r--r--src/SMAPI/IAssetDataForDictionary.cs2
-rw-r--r--src/SMAPI/IAssetDataForImage.cs2
-rw-r--r--src/SMAPI/IAssetDataForMap.cs2
-rw-r--r--src/SMAPI/IAssetEditor.cs2
-rw-r--r--src/SMAPI/IAssetInfo.cs2
-rw-r--r--src/SMAPI/IAssetLoader.cs2
-rw-r--r--src/SMAPI/IAssetName.cs2
-rw-r--r--src/SMAPI/ICommandHelper.cs2
-rw-r--r--src/SMAPI/IContentHelper.cs2
-rw-r--r--src/SMAPI/IContentPack.cs2
-rw-r--r--src/SMAPI/IContentPackHelper.cs2
-rw-r--r--src/SMAPI/ICursorPosition.cs2
-rw-r--r--src/SMAPI/IDataHelper.cs2
-rw-r--r--src/SMAPI/IGameContentHelper.cs2
-rw-r--r--src/SMAPI/IInputHelper.cs2
-rw-r--r--src/SMAPI/IMod.cs2
-rw-r--r--src/SMAPI/IModContentHelper.cs2
-rw-r--r--src/SMAPI/IModHelper.cs2
-rw-r--r--src/SMAPI/IModInfo.cs2
-rw-r--r--src/SMAPI/IModLinked.cs2
-rw-r--r--src/SMAPI/IModRegistry.cs2
-rw-r--r--src/SMAPI/IMonitor.cs2
-rw-r--r--src/SMAPI/IMultiplayerHelper.cs2
-rw-r--r--src/SMAPI/IMultiplayerPeer.cs2
-rw-r--r--src/SMAPI/IMultiplayerPeerMod.cs2
-rw-r--r--src/SMAPI/IReflectedField.cs4
-rw-r--r--src/SMAPI/IReflectedMethod.cs4
-rw-r--r--src/SMAPI/IReflectedProperty.cs2
-rw-r--r--src/SMAPI/IReflectionHelper.cs2
-rw-r--r--src/SMAPI/ITranslationHelper.cs2
-rw-r--r--src/SMAPI/Metadata/CoreAssetPropagator.cs8
-rw-r--r--src/SMAPI/Metadata/InstructionMetadata.cs2
-rw-r--r--src/SMAPI/Mod.cs2
-rw-r--r--src/SMAPI/Patches/Game1Patcher.cs2
-rw-r--r--src/SMAPI/Patches/TitleMenuPatcher.cs2
-rw-r--r--src/SMAPI/Program.cs6
-rw-r--r--src/SMAPI/SButton.cs2
-rw-r--r--src/SMAPI/SButtonState.cs2
-rw-r--r--src/SMAPI/SMAPI.config.json5
-rw-r--r--src/SMAPI/SemanticVersion.cs29
-rw-r--r--src/SMAPI/Translation.cs4
-rw-r--r--src/SMAPI/Utilities/CaseInsensitivePathCache.cs126
-rw-r--r--src/SMAPI/Utilities/Keybind.cs6
-rw-r--r--src/SMAPI/Utilities/KeybindList.cs4
-rw-r--r--src/SMAPI/Utilities/PathUtilities.cs14
-rw-r--r--src/SMAPI/Utilities/PerScreen.cs4
-rw-r--r--src/SMAPI/Utilities/SDate.cs2
263 files changed, 1091 insertions, 389 deletions
diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs
index 76f4ef87..2d9ab666 100644
--- a/src/SMAPI/Constants.cs
+++ b/src/SMAPI/Constants.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.IO;
@@ -170,9 +172,6 @@ namespace StardewModdingAPI
/// <summary>The target game platform as a SMAPI toolkit constant.</summary>
internal static Platform Platform { get; } = (Platform)Constants.TargetPlatform;
- /// <summary>The language code for non-translated mod assets.</summary>
- internal static LocalizedContentManager.LanguageCode DefaultLanguage { get; } = LocalizedContentManager.LanguageCode.en;
-
/*********
** Internal methods
@@ -294,21 +293,6 @@ namespace StardewModdingAPI
return new PlatformAssemblyMap(targetPlatform, removeAssemblyReferences.ToArray(), targetAssemblies.ToArray());
}
- /// <summary>Get whether the game assembly was patched by Stardew64Installer.</summary>
- /// <param name="version">The version of Stardew64Installer which was applied to the game assembly, if any.</param>
- internal static bool IsPatchedByStardew64Installer(out ISemanticVersion version)
- {
- PropertyInfo property = typeof(Game1).GetProperty("Stardew64InstallerVersion");
- if (property == null)
- {
- version = null;
- return false;
- }
-
- version = new SemanticVersion((string)property.GetValue(null));
- return true;
- }
-
/*********
** Private methods
diff --git a/src/SMAPI/Context.cs b/src/SMAPI/Context.cs
index a745592c..e906375b 100644
--- a/src/SMAPI/Context.cs
+++ b/src/SMAPI/Context.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using StardewModdingAPI.Enums;
using StardewModdingAPI.Events;
@@ -14,16 +16,16 @@ namespace StardewModdingAPI
** Fields
*********/
/// <summary>Whether the player has loaded a save and the world has finished initializing.</summary>
- private static readonly PerScreen<bool> IsWorldReadyForScreen = new PerScreen<bool>();
+ private static readonly PerScreen<bool> IsWorldReadyForScreen = new();
/// <summary>The current stage in the game's loading process.</summary>
- private static readonly PerScreen<LoadStage> LoadStageForScreen = new PerScreen<LoadStage>();
+ private static readonly PerScreen<LoadStage> LoadStageForScreen = new();
/// <summary>Whether a player save has been loaded.</summary>
- internal static bool IsSaveLoaded => Game1.hasLoadedGame && !(Game1.activeClickableMenu is TitleMenu);
+ internal static bool IsSaveLoaded => Game1.hasLoadedGame && Game1.activeClickableMenu is not TitleMenu;
/// <summary>Whether the game is currently writing to the save file.</summary>
- internal static bool IsSaving => Game1.activeClickableMenu is SaveGameMenu || Game1.activeClickableMenu is ShippingMenu; // saving is performed by SaveGameMenu, but it's wrapped by ShippingMenu on days when the player shipping something
+ internal static bool IsSaving => Game1.activeClickableMenu is SaveGameMenu or ShippingMenu; // saving is performed by SaveGameMenu, but it's wrapped by ShippingMenu on days when the player shipping something
/// <summary>The active split-screen instance IDs.</summary>
internal static readonly ISet<int> ActiveScreenIds = new HashSet<int>();
@@ -39,7 +41,7 @@ namespace StardewModdingAPI
}
/// <summary>Whether the in-game world is completely unloaded and not in the process of being loaded. The world may still exist in memory at this point, but should be ignored.</summary>
- internal static bool IsWorldFullyUnloaded => Context.LoadStage == LoadStage.ReturningToTitle || Context.LoadStage == LoadStage.None;
+ internal static bool IsWorldFullyUnloaded => Context.LoadStage is LoadStage.ReturningToTitle or LoadStage.None;
/*********
@@ -86,7 +88,7 @@ namespace StardewModdingAPI
public static bool HasRemotePlayers => Context.IsMultiplayer && !Game1.hasLocalClientsOnly;
/// <summary>Whether the current player is the main player. This is always true in single-player, and true when hosting in multiplayer.</summary>
- public static bool IsMainPlayer => Game1.IsMasterGame && Context.ScreenId == 0 && !(TitleMenu.subMenu is FarmhandMenu);
+ public static bool IsMainPlayer => Game1.IsMasterGame && Context.ScreenId == 0 && TitleMenu.subMenu is not FarmhandMenu;
/*********
diff --git a/src/SMAPI/Events/AssetReadyEventArgs.cs b/src/SMAPI/Events/AssetReadyEventArgs.cs
index 2c308f18..19e5a9df 100644
--- a/src/SMAPI/Events/AssetReadyEventArgs.cs
+++ b/src/SMAPI/Events/AssetReadyEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Events
diff --git a/src/SMAPI/Events/AssetRequestedEventArgs.cs b/src/SMAPI/Events/AssetRequestedEventArgs.cs
index c0cbd8fb..3c51c95d 100644
--- a/src/SMAPI/Events/AssetRequestedEventArgs.cs
+++ b/src/SMAPI/Events/AssetRequestedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
@@ -99,7 +101,7 @@ namespace StardewModdingAPI.Events
mod: this.Mod,
priority: priority,
onBehalfOf: null,
- _ => this.Mod.Mod.Helper.Content.Load<TAsset>(relativePath))
+ _ => this.Mod.Mod.Helper.ModContent.Load<TAsset>(relativePath))
);
}
diff --git a/src/SMAPI/Events/AssetsInvalidatedEventArgs.cs b/src/SMAPI/Events/AssetsInvalidatedEventArgs.cs
index 614cdf49..bd0df598 100644
--- a/src/SMAPI/Events/AssetsInvalidatedEventArgs.cs
+++ b/src/SMAPI/Events/AssetsInvalidatedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
diff --git a/src/SMAPI/Events/BuildingListChangedEventArgs.cs b/src/SMAPI/Events/BuildingListChangedEventArgs.cs
index 74f37710..ba9574cc 100644
--- a/src/SMAPI/Events/BuildingListChangedEventArgs.cs
+++ b/src/SMAPI/Events/BuildingListChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/SMAPI/Events/ButtonPressedEventArgs.cs b/src/SMAPI/Events/ButtonPressedEventArgs.cs
index 1b30fd23..94684513 100644
--- a/src/SMAPI/Events/ButtonPressedEventArgs.cs
+++ b/src/SMAPI/Events/ButtonPressedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Framework.Input;
diff --git a/src/SMAPI/Events/ButtonReleasedEventArgs.cs b/src/SMAPI/Events/ButtonReleasedEventArgs.cs
index 40ec1cc1..6ff3727d 100644
--- a/src/SMAPI/Events/ButtonReleasedEventArgs.cs
+++ b/src/SMAPI/Events/ButtonReleasedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Framework.Input;
diff --git a/src/SMAPI/Events/ButtonsChangedEventArgs.cs b/src/SMAPI/Events/ButtonsChangedEventArgs.cs
index a5e87735..c63d34e6 100644
--- a/src/SMAPI/Events/ButtonsChangedEventArgs.cs
+++ b/src/SMAPI/Events/ButtonsChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/SMAPI/Events/ChestInventoryChangedEventArgs.cs b/src/SMAPI/Events/ChestInventoryChangedEventArgs.cs
index 4b4c4210..bc8ac0c0 100644
--- a/src/SMAPI/Events/ChestInventoryChangedEventArgs.cs
+++ b/src/SMAPI/Events/ChestInventoryChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using StardewValley;
diff --git a/src/SMAPI/Events/CursorMovedEventArgs.cs b/src/SMAPI/Events/CursorMovedEventArgs.cs
index 43ff90ce..f3e7513b 100644
--- a/src/SMAPI/Events/CursorMovedEventArgs.cs
+++ b/src/SMAPI/Events/CursorMovedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Events
diff --git a/src/SMAPI/Events/DebrisListChangedEventArgs.cs b/src/SMAPI/Events/DebrisListChangedEventArgs.cs
index 61b7590a..56b1f30a 100644
--- a/src/SMAPI/Events/DebrisListChangedEventArgs.cs
+++ b/src/SMAPI/Events/DebrisListChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/SMAPI/Events/FurnitureListChangedEventArgs.cs b/src/SMAPI/Events/FurnitureListChangedEventArgs.cs
index 683f4620..cda1b6cc 100644
--- a/src/SMAPI/Events/FurnitureListChangedEventArgs.cs
+++ b/src/SMAPI/Events/FurnitureListChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/SMAPI/Events/IContentEvents.cs b/src/SMAPI/Events/IContentEvents.cs
index d537db70..109f9753 100644
--- a/src/SMAPI/Events/IContentEvents.cs
+++ b/src/SMAPI/Events/IContentEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Events
diff --git a/src/SMAPI/Events/IDisplayEvents.cs b/src/SMAPI/Events/IDisplayEvents.cs
index dbf8d90f..b8b89120 100644
--- a/src/SMAPI/Events/IDisplayEvents.cs
+++ b/src/SMAPI/Events/IDisplayEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewValley;
diff --git a/src/SMAPI/Events/IGameLoopEvents.cs b/src/SMAPI/Events/IGameLoopEvents.cs
index 6855737b..52bac3f8 100644
--- a/src/SMAPI/Events/IGameLoopEvents.cs
+++ b/src/SMAPI/Events/IGameLoopEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Events
diff --git a/src/SMAPI/Events/IInputEvents.cs b/src/SMAPI/Events/IInputEvents.cs
index 081c40c0..01ceb224 100644
--- a/src/SMAPI/Events/IInputEvents.cs
+++ b/src/SMAPI/Events/IInputEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Events
diff --git a/src/SMAPI/Events/IModEvents.cs b/src/SMAPI/Events/IModEvents.cs
index 2603961b..a1aacbce 100644
--- a/src/SMAPI/Events/IModEvents.cs
+++ b/src/SMAPI/Events/IModEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI.Events
{
/// <summary>Manages access to events raised by SMAPI.</summary>
diff --git a/src/SMAPI/Events/IMultiplayerEvents.cs b/src/SMAPI/Events/IMultiplayerEvents.cs
index af9b5f17..c50eaf04 100644
--- a/src/SMAPI/Events/IMultiplayerEvents.cs
+++ b/src/SMAPI/Events/IMultiplayerEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Events
diff --git a/src/SMAPI/Events/IPlayerEvents.cs b/src/SMAPI/Events/IPlayerEvents.cs
index 81e17b1a..9d18bfad 100644
--- a/src/SMAPI/Events/IPlayerEvents.cs
+++ b/src/SMAPI/Events/IPlayerEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Events
diff --git a/src/SMAPI/Events/ISpecialisedEvents.cs b/src/SMAPI/Events/ISpecialisedEvents.cs
index bf70956d..0ec5bf54 100644
--- a/src/SMAPI/Events/ISpecialisedEvents.cs
+++ b/src/SMAPI/Events/ISpecialisedEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Events
diff --git a/src/SMAPI/Events/IWorldEvents.cs b/src/SMAPI/Events/IWorldEvents.cs
index c023e1f0..785dfa8f 100644
--- a/src/SMAPI/Events/IWorldEvents.cs
+++ b/src/SMAPI/Events/IWorldEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Events
diff --git a/src/SMAPI/Events/InventoryChangedEventArgs.cs b/src/SMAPI/Events/InventoryChangedEventArgs.cs
index 40cd4128..58c0ff8f 100644
--- a/src/SMAPI/Events/InventoryChangedEventArgs.cs
+++ b/src/SMAPI/Events/InventoryChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using StardewValley;
diff --git a/src/SMAPI/Events/ItemStackSizeChange.cs b/src/SMAPI/Events/ItemStackSizeChange.cs
index 35369be2..5d0986aa 100644
--- a/src/SMAPI/Events/ItemStackSizeChange.cs
+++ b/src/SMAPI/Events/ItemStackSizeChange.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using StardewValley;
namespace StardewModdingAPI.Events
diff --git a/src/SMAPI/Events/LargeTerrainFeatureListChangedEventArgs.cs b/src/SMAPI/Events/LargeTerrainFeatureListChangedEventArgs.cs
index 59d79f0f..aedb0e46 100644
--- a/src/SMAPI/Events/LargeTerrainFeatureListChangedEventArgs.cs
+++ b/src/SMAPI/Events/LargeTerrainFeatureListChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/SMAPI/Events/LevelChangedEventArgs.cs b/src/SMAPI/Events/LevelChangedEventArgs.cs
index c7303603..3beb9fd5 100644
--- a/src/SMAPI/Events/LevelChangedEventArgs.cs
+++ b/src/SMAPI/Events/LevelChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Enums;
using StardewValley;
diff --git a/src/SMAPI/Events/LocaleChangedEventArgs.cs b/src/SMAPI/Events/LocaleChangedEventArgs.cs
index 09d3f6e5..015e7ec8 100644
--- a/src/SMAPI/Events/LocaleChangedEventArgs.cs
+++ b/src/SMAPI/Events/LocaleChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using LanguageCode = StardewValley.LocalizedContentManager.LanguageCode;
diff --git a/src/SMAPI/Events/LocationListChangedEventArgs.cs b/src/SMAPI/Events/LocationListChangedEventArgs.cs
index 1ebb3e2d..055463dd 100644
--- a/src/SMAPI/Events/LocationListChangedEventArgs.cs
+++ b/src/SMAPI/Events/LocationListChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/SMAPI/Events/MenuChangedEventArgs.cs b/src/SMAPI/Events/MenuChangedEventArgs.cs
index 977ba38b..362accec 100644
--- a/src/SMAPI/Events/MenuChangedEventArgs.cs
+++ b/src/SMAPI/Events/MenuChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewValley.Menus;
diff --git a/src/SMAPI/Events/ModMessageReceivedEventArgs.cs b/src/SMAPI/Events/ModMessageReceivedEventArgs.cs
index d75a7540..671bdf38 100644
--- a/src/SMAPI/Events/ModMessageReceivedEventArgs.cs
+++ b/src/SMAPI/Events/ModMessageReceivedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Framework.Networking;
using StardewModdingAPI.Toolkit.Serialization;
diff --git a/src/SMAPI/Events/NpcListChangedEventArgs.cs b/src/SMAPI/Events/NpcListChangedEventArgs.cs
index 3a37f1e7..fb6dc1c5 100644
--- a/src/SMAPI/Events/NpcListChangedEventArgs.cs
+++ b/src/SMAPI/Events/NpcListChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/SMAPI/Events/ObjectListChangedEventArgs.cs b/src/SMAPI/Events/ObjectListChangedEventArgs.cs
index b21d2867..b1a636aa 100644
--- a/src/SMAPI/Events/ObjectListChangedEventArgs.cs
+++ b/src/SMAPI/Events/ObjectListChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/SMAPI/Events/PeerConnectedEventArgs.cs b/src/SMAPI/Events/PeerConnectedEventArgs.cs
index bfaa2bd3..3d11a3b5 100644
--- a/src/SMAPI/Events/PeerConnectedEventArgs.cs
+++ b/src/SMAPI/Events/PeerConnectedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Events
diff --git a/src/SMAPI/Events/PeerContextReceivedEventArgs.cs b/src/SMAPI/Events/PeerContextReceivedEventArgs.cs
index 151a295c..35a4b20d 100644
--- a/src/SMAPI/Events/PeerContextReceivedEventArgs.cs
+++ b/src/SMAPI/Events/PeerContextReceivedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Events
diff --git a/src/SMAPI/Events/PeerDisconnectedEventArgs.cs b/src/SMAPI/Events/PeerDisconnectedEventArgs.cs
index 8517988a..0675b8fe 100644
--- a/src/SMAPI/Events/PeerDisconnectedEventArgs.cs
+++ b/src/SMAPI/Events/PeerDisconnectedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Events
diff --git a/src/SMAPI/Events/RenderedActiveMenuEventArgs.cs b/src/SMAPI/Events/RenderedActiveMenuEventArgs.cs
index efd4163b..3da0b4b4 100644
--- a/src/SMAPI/Events/RenderedActiveMenuEventArgs.cs
+++ b/src/SMAPI/Events/RenderedActiveMenuEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Microsoft.Xna.Framework.Graphics;
using StardewValley;
diff --git a/src/SMAPI/Events/RenderedEventArgs.cs b/src/SMAPI/Events/RenderedEventArgs.cs
index d6341b19..e8beaaac 100644
--- a/src/SMAPI/Events/RenderedEventArgs.cs
+++ b/src/SMAPI/Events/RenderedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Microsoft.Xna.Framework.Graphics;
using StardewValley;
diff --git a/src/SMAPI/Events/RenderedHudEventArgs.cs b/src/SMAPI/Events/RenderedHudEventArgs.cs
index 46e89013..b25ecd4c 100644
--- a/src/SMAPI/Events/RenderedHudEventArgs.cs
+++ b/src/SMAPI/Events/RenderedHudEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Microsoft.Xna.Framework.Graphics;
using StardewValley;
diff --git a/src/SMAPI/Events/RenderedWorldEventArgs.cs b/src/SMAPI/Events/RenderedWorldEventArgs.cs
index 56145381..a99d6ab3 100644
--- a/src/SMAPI/Events/RenderedWorldEventArgs.cs
+++ b/src/SMAPI/Events/RenderedWorldEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Microsoft.Xna.Framework.Graphics;
using StardewValley;
diff --git a/src/SMAPI/Events/RenderingActiveMenuEventArgs.cs b/src/SMAPI/Events/RenderingActiveMenuEventArgs.cs
index 103f56df..3e3f3258 100644
--- a/src/SMAPI/Events/RenderingActiveMenuEventArgs.cs
+++ b/src/SMAPI/Events/RenderingActiveMenuEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Microsoft.Xna.Framework.Graphics;
using StardewValley;
diff --git a/src/SMAPI/Events/RenderingEventArgs.cs b/src/SMAPI/Events/RenderingEventArgs.cs
index 5acbef09..8f6b3557 100644
--- a/src/SMAPI/Events/RenderingEventArgs.cs
+++ b/src/SMAPI/Events/RenderingEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Microsoft.Xna.Framework.Graphics;
using StardewValley;
diff --git a/src/SMAPI/Events/RenderingHudEventArgs.cs b/src/SMAPI/Events/RenderingHudEventArgs.cs
index 84c96ecd..87269b90 100644
--- a/src/SMAPI/Events/RenderingHudEventArgs.cs
+++ b/src/SMAPI/Events/RenderingHudEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Microsoft.Xna.Framework.Graphics;
using StardewValley;
diff --git a/src/SMAPI/Events/RenderingWorldEventArgs.cs b/src/SMAPI/Events/RenderingWorldEventArgs.cs
index d0d44789..2fc9964f 100644
--- a/src/SMAPI/Events/RenderingWorldEventArgs.cs
+++ b/src/SMAPI/Events/RenderingWorldEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Microsoft.Xna.Framework.Graphics;
using StardewValley;
diff --git a/src/SMAPI/Events/TerrainFeatureListChangedEventArgs.cs b/src/SMAPI/Events/TerrainFeatureListChangedEventArgs.cs
index cdf1e6dc..77a73102 100644
--- a/src/SMAPI/Events/TerrainFeatureListChangedEventArgs.cs
+++ b/src/SMAPI/Events/TerrainFeatureListChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/SMAPI/Events/WarpedEventArgs.cs b/src/SMAPI/Events/WarpedEventArgs.cs
index 9afe4a4e..92a8ea77 100644
--- a/src/SMAPI/Events/WarpedEventArgs.cs
+++ b/src/SMAPI/Events/WarpedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewValley;
diff --git a/src/SMAPI/Framework/Command.cs b/src/SMAPI/Framework/Command.cs
index 8c9df47d..776ba238 100644
--- a/src/SMAPI/Framework/Command.cs
+++ b/src/SMAPI/Framework/Command.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Framework
diff --git a/src/SMAPI/Framework/CommandManager.cs b/src/SMAPI/Framework/CommandManager.cs
index ff540ad8..df798b0c 100644
--- a/src/SMAPI/Framework/CommandManager.cs
+++ b/src/SMAPI/Framework/CommandManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -65,7 +67,7 @@ namespace StardewModdingAPI.Framework
/// <exception cref="ArgumentException">There's already a command with that name.</exception>
public CommandManager Add(IInternalCommand command, IMonitor monitor)
{
- return this.Add(null, command.Name, command.Description, (name, args) => command.HandleCommand(args, monitor));
+ return this.Add(null, command.Name, command.Description, (_, args) => command.HandleCommand(args, monitor));
}
/// <summary>Get a command by its unique name.</summary>
@@ -166,7 +168,7 @@ namespace StardewModdingAPI.Framework
{
bool inQuotes = false;
IList<string> args = new List<string>();
- StringBuilder currentArg = new StringBuilder();
+ StringBuilder currentArg = new();
foreach (char ch in input)
{
if (ch == '"')
diff --git a/src/SMAPI/Framework/Commands/HarmonySummaryCommand.cs b/src/SMAPI/Framework/Commands/HarmonySummaryCommand.cs
index 45b34556..fcfa928e 100644
--- a/src/SMAPI/Framework/Commands/HarmonySummaryCommand.cs
+++ b/src/SMAPI/Framework/Commands/HarmonySummaryCommand.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -30,7 +32,7 @@ namespace StardewModdingAPI.Framework.Commands
{
SearchResult[] matches = this.FilterPatches(args).OrderBy(p => p.MethodName).ToArray();
- StringBuilder result = new StringBuilder();
+ StringBuilder result = new();
if (!matches.Any())
result.AppendLine("No current patches match your search.");
diff --git a/src/SMAPI/Framework/Commands/HelpCommand.cs b/src/SMAPI/Framework/Commands/HelpCommand.cs
index baf3116e..eb6c74f5 100644
--- a/src/SMAPI/Framework/Commands/HelpCommand.cs
+++ b/src/SMAPI/Framework/Commands/HelpCommand.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Linq;
namespace StardewModdingAPI.Framework.Commands
diff --git a/src/SMAPI/Framework/Commands/IInternalCommand.cs b/src/SMAPI/Framework/Commands/IInternalCommand.cs
index abf105b6..32e3e9f1 100644
--- a/src/SMAPI/Framework/Commands/IInternalCommand.cs
+++ b/src/SMAPI/Framework/Commands/IInternalCommand.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI.Framework.Commands
{
/// <summary>A core SMAPI console command.</summary>
diff --git a/src/SMAPI/Framework/Commands/ReloadI18nCommand.cs b/src/SMAPI/Framework/Commands/ReloadI18nCommand.cs
index 12328bb6..2043b35e 100644
--- a/src/SMAPI/Framework/Commands/ReloadI18nCommand.cs
+++ b/src/SMAPI/Framework/Commands/ReloadI18nCommand.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Framework.Commands
diff --git a/src/SMAPI/Framework/Content/AssetData.cs b/src/SMAPI/Framework/Content/AssetData.cs
index 05be8a3b..be4a7ce6 100644
--- a/src/SMAPI/Framework/Content/AssetData.cs
+++ b/src/SMAPI/Framework/Content/AssetData.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Framework.Content
diff --git a/src/SMAPI/Framework/Content/AssetDataForDictionary.cs b/src/SMAPI/Framework/Content/AssetDataForDictionary.cs
index 735b651c..06dbe259 100644
--- a/src/SMAPI/Framework/Content/AssetDataForDictionary.cs
+++ b/src/SMAPI/Framework/Content/AssetDataForDictionary.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
diff --git a/src/SMAPI/Framework/Content/AssetDataForImage.cs b/src/SMAPI/Framework/Content/AssetDataForImage.cs
index b0f1b5c7..8e59cd27 100644
--- a/src/SMAPI/Framework/Content/AssetDataForImage.cs
+++ b/src/SMAPI/Framework/Content/AssetDataForImage.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
diff --git a/src/SMAPI/Framework/Content/AssetDataForMap.cs b/src/SMAPI/Framework/Content/AssetDataForMap.cs
index 26e4986e..0425e195 100644
--- a/src/SMAPI/Framework/Content/AssetDataForMap.cs
+++ b/src/SMAPI/Framework/Content/AssetDataForMap.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -96,8 +98,8 @@ namespace StardewModdingAPI.Framework.Content
for (int y = 0; y < sourceArea.Value.Height; y++)
{
// calculate tile positions
- Point sourcePos = new Point(sourceArea.Value.X + x, sourceArea.Value.Y + y);
- Point targetPos = new Point(targetArea.Value.X + x, targetArea.Value.Y + y);
+ Point sourcePos = new(sourceArea.Value.X + x, sourceArea.Value.Y + y);
+ Point targetPos = new(targetArea.Value.X + x, targetArea.Value.Y + y);
// replace tiles on target-only layers
if (replaceAll)
@@ -147,7 +149,7 @@ namespace StardewModdingAPI.Framework.Content
{
switch (sourceTile)
{
- case StaticTile _:
+ case StaticTile:
return new StaticTile(targetLayer, targetSheet, sourceTile.BlendMode, sourceTile.TileIndex);
case AnimatedTile animatedTile:
diff --git a/src/SMAPI/Framework/Content/AssetDataForObject.cs b/src/SMAPI/Framework/Content/AssetDataForObject.cs
index d91873ae..4a6df64b 100644
--- a/src/SMAPI/Framework/Content/AssetDataForObject.cs
+++ b/src/SMAPI/Framework/Content/AssetDataForObject.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
@@ -47,9 +49,9 @@ namespace StardewModdingAPI.Framework.Content
/// <inheritdoc />
public TData GetData<TData>()
{
- if (!(this.Data is TData))
+ if (this.Data is not TData data)
throw new InvalidCastException($"The content data of type {this.Data.GetType().FullName} can't be converted to the requested {typeof(TData).FullName}.");
- return (TData)this.Data;
+ return data;
}
}
}
diff --git a/src/SMAPI/Framework/Content/AssetEditOperation.cs b/src/SMAPI/Framework/Content/AssetEditOperation.cs
index 818209fa..1b7d0c93 100644
--- a/src/SMAPI/Framework/Content/AssetEditOperation.cs
+++ b/src/SMAPI/Framework/Content/AssetEditOperation.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Events;
diff --git a/src/SMAPI/Framework/Content/AssetInfo.cs b/src/SMAPI/Framework/Content/AssetInfo.cs
index f5da5d69..51dcc61f 100644
--- a/src/SMAPI/Framework/Content/AssetInfo.cs
+++ b/src/SMAPI/Framework/Content/AssetInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
diff --git a/src/SMAPI/Framework/Content/AssetInterceptorChange.cs b/src/SMAPI/Framework/Content/AssetInterceptorChange.cs
index 981eed40..7f53db9b 100644
--- a/src/SMAPI/Framework/Content/AssetInterceptorChange.cs
+++ b/src/SMAPI/Framework/Content/AssetInterceptorChange.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Reflection;
using StardewModdingAPI.Internal;
@@ -36,7 +38,7 @@ namespace StardewModdingAPI.Framework.Content
this.Instance = instance ?? throw new ArgumentNullException(nameof(instance));
this.WasAdded = wasAdded;
- if (!(instance is IAssetEditor) && !(instance is IAssetLoader))
+ if (instance is not (IAssetEditor or IAssetLoader))
throw new InvalidCastException($"The provided {nameof(instance)} value must be an {nameof(IAssetEditor)} or {nameof(IAssetLoader)} instance.");
}
diff --git a/src/SMAPI/Framework/Content/AssetLoadOperation.cs b/src/SMAPI/Framework/Content/AssetLoadOperation.cs
index b12958d6..73e60e24 100644
--- a/src/SMAPI/Framework/Content/AssetLoadOperation.cs
+++ b/src/SMAPI/Framework/Content/AssetLoadOperation.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Events;
diff --git a/src/SMAPI/Framework/Content/AssetName.cs b/src/SMAPI/Framework/Content/AssetName.cs
index a1d37b0b..4d583d82 100644
--- a/src/SMAPI/Framework/Content/AssetName.cs
+++ b/src/SMAPI/Framework/Content/AssetName.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Toolkit.Utilities;
using StardewValley;
@@ -107,7 +109,7 @@ namespace StardewModdingAPI.Framework.Content
return this.BaseName.Equals(assetName?.BaseName, StringComparison.OrdinalIgnoreCase);
if (assetName is AssetName impl)
- return this.ComparableName == impl?.ComparableName;
+ return this.ComparableName == impl.ComparableName;
return this.Name.Equals(assetName?.Name, StringComparison.OrdinalIgnoreCase);
}
diff --git a/src/SMAPI/Framework/Content/AssetOperationGroup.cs b/src/SMAPI/Framework/Content/AssetOperationGroup.cs
index a2fcb722..e3c3f92c 100644
--- a/src/SMAPI/Framework/Content/AssetOperationGroup.cs
+++ b/src/SMAPI/Framework/Content/AssetOperationGroup.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI.Framework.Content
{
/// <summary>A set of operations to apply to an asset for a given <see cref="IAssetEditor"/> or <see cref="IAssetLoader"/> implementation.</summary>
diff --git a/src/SMAPI/Framework/Content/ContentCache.cs b/src/SMAPI/Framework/Content/ContentCache.cs
index 8e0c6228..4e620d28 100644
--- a/src/SMAPI/Framework/Content/ContentCache.cs
+++ b/src/SMAPI/Framework/Content/ContentCache.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
diff --git a/src/SMAPI/Framework/Content/TilesheetReference.cs b/src/SMAPI/Framework/Content/TilesheetReference.cs
index 0919bb44..cdc4bc62 100644
--- a/src/SMAPI/Framework/Content/TilesheetReference.cs
+++ b/src/SMAPI/Framework/Content/TilesheetReference.cs
@@ -1,4 +1,5 @@
-using System.Numerics;
+#nullable disable
+
using xTile.Dimensions;
namespace StardewModdingAPI.Framework.Content
diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs
index 108257bf..81820b05 100644
--- a/src/SMAPI/Framework/ContentCoordinator.cs
+++ b/src/SMAPI/Framework/ContentCoordinator.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
@@ -15,7 +17,7 @@ using StardewModdingAPI.Framework.Utilities;
using StardewModdingAPI.Internal;
using StardewModdingAPI.Metadata;
using StardewModdingAPI.Toolkit.Serialization;
-using StardewModdingAPI.Toolkit.Utilities;
+using StardewModdingAPI.Utilities;
using StardewValley;
using StardewValley.GameData;
using xTile;
@@ -80,6 +82,9 @@ namespace StardewModdingAPI.Framework
/// <summary>The cached asset load/edit operations to apply, indexed by asset name.</summary>
private readonly TickCacheDictionary<IAssetName, AssetOperationGroup[]> AssetOperationsByKey = new();
+ /// <summary>The previously created case-insensitive path caches by root path.</summary>
+ private readonly Dictionary<string, CaseInsensitivePathCache> CaseInsensitivePathCaches = new(StringComparer.OrdinalIgnoreCase);
+
/*********
** Accessors
@@ -91,9 +96,11 @@ namespace StardewModdingAPI.Framework
public LocalizedContentManager.LanguageCode Language => this.MainContentManager.Language;
/// <summary>Interceptors which provide the initial versions of matching assets.</summary>
+ [Obsolete]
public IList<ModLinked<IAssetLoader>> Loaders { get; } = new List<ModLinked<IAssetLoader>>();
/// <summary>Interceptors which edit matching assets after they're loaded.</summary>
+ [Obsolete]
public IList<ModLinked<IAssetEditor>> Editors { get; } = new List<ModLinked<IAssetEditor>>();
/// <summary>The absolute path to the <see cref="ContentManager.RootDirectory"/>.</summary>
@@ -156,7 +163,7 @@ namespace StardewModdingAPI.Framework
);
this.ContentManagers.Add(contentManagerForAssetPropagation);
this.VanillaContentManager = new LocalizedContentManager(serviceProvider, rootDirectory);
- this.CoreAssets = new CoreAssetPropagator(this.MainContentManager, contentManagerForAssetPropagation, this.Monitor, reflection, aggressiveMemoryOptimizations, this.ParseAssetName);
+ this.CoreAssets = new CoreAssetPropagator(this.MainContentManager, contentManagerForAssetPropagation, this.Monitor, reflection, aggressiveMemoryOptimizations, name => this.ParseAssetName(name, allowLocales: true));
this.LocaleCodes = new Lazy<Dictionary<string, LocalizedContentManager.LanguageCode>>(() => this.GetLocaleCodes(customLanguages: Enumerable.Empty<ModLanguage>()));
}
@@ -205,7 +212,8 @@ namespace StardewModdingAPI.Framework
reflection: this.Reflection,
jsonHelper: this.JsonHelper,
onDisposing: this.OnDisposing,
- aggressiveMemoryOptimizations: this.AggressiveMemoryOptimizations
+ aggressiveMemoryOptimizations: this.AggressiveMemoryOptimizations,
+ relativePathCache: this.GetCaseInsensitivePathCache(rootDirectory)
);
this.ContentManagers.Add(manager);
return manager;
@@ -269,11 +277,17 @@ namespace StardewModdingAPI.Framework
/// <summary>Parse a raw asset name.</summary>
/// <param name="rawName">The raw asset name to parse.</param>
+ /// <param name="allowLocales">Whether to parse locales in the <paramref name="rawName"/>. If this is false, any locale codes in the name are treated as if they were part of the base name (e.g. for mod files).</param>
/// <exception cref="ArgumentException">The <paramref name="rawName"/> is null or empty.</exception>
- public AssetName ParseAssetName(string rawName)
+ public AssetName ParseAssetName(string rawName, bool allowLocales)
{
return !string.IsNullOrWhiteSpace(rawName)
- ? AssetName.Parse(rawName, parseLocale: locale => this.LocaleCodes.Value.TryGetValue(locale, out LocalizedContentManager.LanguageCode langCode) ? langCode : null)
+ ? AssetName.Parse(
+ rawName: rawName,
+ parseLocale: allowLocales
+ ? locale => this.LocaleCodes.Value.TryGetValue(locale, out LocalizedContentManager.LanguageCode langCode) ? langCode : null
+ : _ => null
+ )
: throw new ArgumentException("The asset name can't be null or empty.", nameof(rawName));
}
@@ -303,7 +317,7 @@ namespace StardewModdingAPI.Framework
if (parts.Length != 3) // managed key prefix, mod id, relative path
return false;
contentManagerID = Path.Combine(parts[0], parts[1]);
- relativePath = this.ParseAssetName(parts[2]);
+ relativePath = this.ParseAssetName(parts[2], allowLocales: false);
return true;
}
@@ -357,7 +371,7 @@ namespace StardewModdingAPI.Framework
string locale = this.GetLocale();
return this.InvalidateCache((_, rawName, type) =>
{
- IAssetName assetName = this.ParseAssetName(rawName);
+ IAssetName assetName = this.ParseAssetName(rawName, allowLocales: true);
IAssetInfo info = new AssetInfo(locale, assetName, type, this.MainContentManager.AssertAndNormalizeAssetName);
return predicate(info);
}, dispose);
@@ -378,7 +392,7 @@ namespace StardewModdingAPI.Framework
{
foreach ((string key, object asset) in contentManager.InvalidateCache((key, type) => predicate(contentManager, key, type), dispose))
{
- AssetName assetName = this.ParseAssetName(key);
+ AssetName assetName = this.ParseAssetName(key, allowLocales: true);
if (!invalidatedAssets.ContainsKey(assetName))
invalidatedAssets[assetName] = asset.GetType();
}
@@ -394,7 +408,7 @@ namespace StardewModdingAPI.Framework
continue;
// get map path
- AssetName mapPath = this.ParseAssetName(this.MainContentManager.AssertAndNormalizeAssetName(location.mapPath.Value));
+ AssetName mapPath = this.ParseAssetName(this.MainContentManager.AssertAndNormalizeAssetName(location.mapPath.Value), allowLocales: true);
if (!invalidatedAssets.ContainsKey(mapPath) && predicate(this.MainContentManager, mapPath.Name, typeof(Map)))
invalidatedAssets[mapPath] = typeof(Map);
}
@@ -471,6 +485,18 @@ namespace StardewModdingAPI.Framework
});
}
+ /// <summary>Get a dictionary of relative paths within a root path, for case-insensitive file lookups.</summary>
+ /// <param name="rootPath">The root path to scan.</param>
+ public CaseInsensitivePathCache GetCaseInsensitivePathCache(string rootPath)
+ {
+ rootPath = PathUtilities.NormalizePath(rootPath);
+
+ if (!this.CaseInsensitivePathCaches.TryGetValue(rootPath, out CaseInsensitivePathCache cache))
+ this.CaseInsensitivePathCaches[rootPath] = cache = new CaseInsensitivePathCache(rootPath);
+
+ return cache;
+ }
+
/// <summary>Get the tilesheet ID order used by the unmodified version of a map asset.</summary>
/// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param>
public TilesheetReference[] GetVanillaTilesheetIds(string assetName)
@@ -584,6 +610,7 @@ namespace StardewModdingAPI.Framework
yield return group;
// legacy load operations
+#pragma warning disable CS0612, CS0618 // deprecated code
foreach (ModLinked<IAssetLoader> loader in this.Loaders)
{
// check if loader applies
@@ -631,6 +658,27 @@ namespace StardewModdingAPI.Framework
continue;
}
+ // HACK
+ //
+ // If two editors have the same priority, they're applied in registration order (so
+ // whichever was registered first is applied first). Mods often depend on this
+ // behavior, like Json Assets registering its interceptors before Content Patcher.
+ //
+ // Unfortunately the old & new content APIs have separate lists, so new-API
+ // interceptors always ran before old-API interceptors with the same priority,
+ // regardless of the registration order *between* APIs. Since the new API works in
+ // a fundamentally different way (i.e. loads/edits are defined on asset request
+ // instead of by registering a global 'editor' or 'loader' class), there's no way
+ // to track registration order between them.
+ //
+ // Until we drop the old content API in SMAPI 4.0.0, this sets the priority for
+ // specific legacy editors to maintain compatibility.
+ AssetEditPriority priority = editor.Data.GetType().FullName switch
+ {
+ "JsonAssets.Framework.ContentInjector1" => AssetEditPriority.Default - 1, // must be applied before Content Patcher
+ _ => AssetEditPriority.Default
+ };
+
// add operation
yield return new AssetOperationGroup(
mod: editor.Mod,
@@ -639,7 +687,7 @@ namespace StardewModdingAPI.Framework
{
new AssetEditOperation(
mod: editor.Mod,
- priority: AssetEditPriority.Default,
+ priority: priority,
onBehalfOf: null,
applyEdit: assetData => editor.Data.Edit<T>(
this.GetLegacyAssetData(assetData)
@@ -648,6 +696,7 @@ namespace StardewModdingAPI.Framework
}
);
}
+#pragma warning restore CS0612, CS0618
}
/// <summary>Get an asset info compatible with legacy <see cref="IAssetLoader"/> and <see cref="IAssetEditor"/> instances, which always expect the base name.</summary>
diff --git a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
index 2d921cc3..4594d235 100644
--- a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
@@ -119,7 +121,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
public sealed override T Load<T>(string assetName, LanguageCode language)
{
assetName = this.PrenormalizeRawAssetName(assetName);
- IAssetName parsedName = this.Coordinator.ParseAssetName(assetName);
+ IAssetName parsedName = this.Coordinator.ParseAssetName(assetName, allowLocales: this.TryLocalizeKeys);
return this.LoadLocalized<T>(parsedName, language, useCache: true);
}
@@ -161,7 +163,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
// use cached key
string rawName = LocalizedContentManager.localizedAssetNames[assetName.Name];
if (assetName.Name != rawName)
- assetName = this.Coordinator.ParseAssetName(rawName);
+ assetName = this.Coordinator.ParseAssetName(rawName, allowLocales: this.TryLocalizeKeys);
return this.LoadExact<T>(assetName, useCache: useCache);
}
@@ -213,7 +215,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
IDictionary<string, object> removeAssets = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
this.Cache.Remove((key, asset) =>
{
- string baseAssetName = this.Coordinator.ParseAssetName(key).BaseName;
+ string baseAssetName = this.Coordinator.ParseAssetName(key, allowLocales: this.TryLocalizeKeys).BaseName;
// check if asset should be removed
bool remove = removeAssets.ContainsKey(baseAssetName);
@@ -308,7 +310,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
{
return useCache
? base.LoadBase<T>(assetName.Name)
- : base.ReadAsset<T>(assetName.Name, disposable => this.Disposables.Add(new WeakReference<IDisposable>(disposable)));
+ : this.ReadAsset<T>(assetName.Name, disposable => this.Disposables.Add(new WeakReference<IDisposable>(disposable)));
}
/// <summary>Add tracking data to an asset and add it to the cache.</summary>
diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
index 3d37e32a..f4e1bda4 100644
--- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -235,7 +237,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
mod.LogAsMod($"Mod incorrectly set asset '{info.Name}'{this.GetOnBehalfOfLabel(editor.OnBehalfOf)} to a null value; ignoring override.", LogLevel.Warn);
asset = GetNewData(prevAsset);
}
- else if (!(asset.Data is T))
+ else if (asset.Data is not T)
{
mod.LogAsMod($"Mod incorrectly set asset '{asset.Name}'{this.GetOnBehalfOfLabel(editor.OnBehalfOf)} to incompatible type '{asset.Data.GetType()}', expected '{typeof(T)}'; ignoring override.", LogLevel.Warn);
asset = GetNewData(prevAsset);
diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs b/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs
index 3f7188da..46d5d24e 100644
--- a/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs
+++ b/src/SMAPI/Framework/ContentManagers/GameContentManagerForAssetPropagation.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Globalization;
using Microsoft.Xna.Framework.Graphics;
diff --git a/src/SMAPI/Framework/ContentManagers/IContentManager.cs b/src/SMAPI/Framework/ContentManagers/IContentManager.cs
index 90095492..c8b2ae64 100644
--- a/src/SMAPI/Framework/ContentManagers/IContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/IContentManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Content;
@@ -36,6 +38,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <summary>Load an asset through the content pipeline, using a localized variant of the <paramref name="assetName"/> if available.</summary>
/// <typeparam name="T">The type of asset to load.</typeparam>
/// <param name="assetName">The asset name relative to the loader root directory.</param>
+ /// <param name="language">The language for which to load the asset.</param>
/// <param name="useCache">Whether to read/write the loaded asset to the asset cache.</param>
T LoadLocalized<T>(IAssetName assetName, LocalizedContentManager.LanguageCode language, bool useCache);
diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
index 63b40d66..8051c296 100644
--- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Globalization;
using System.IO;
@@ -9,7 +11,7 @@ using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI.Framework.Exceptions;
using StardewModdingAPI.Framework.Reflection;
using StardewModdingAPI.Toolkit.Serialization;
-using StardewModdingAPI.Toolkit.Utilities;
+using StardewModdingAPI.Utilities;
using StardewValley;
using xTile;
using xTile.Format;
@@ -32,6 +34,9 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <summary>The game content manager used for map tilesheets not provided by the mod.</summary>
private readonly IContentManager GameContentManager;
+ /// <summary>A case-insensitive lookup of relative paths within the <see cref="ContentManager.RootDirectory"/>.</summary>
+ private readonly CaseInsensitivePathCache RelativePathCache;
+
/// <summary>If a map tilesheet's image source has no file extensions, the file extensions to check for in the local mod folder.</summary>
private readonly string[] LocalTilesheetExtensions = { ".png", ".xnb" };
@@ -52,10 +57,12 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <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>
/// <param name="aggressiveMemoryOptimizations">Whether to enable more aggressive memory optimizations.</param>
- 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, bool aggressiveMemoryOptimizations)
+ /// <param name="relativePathCache">A case-insensitive lookup of relative paths within the <paramref name="rootDirectory"/>.</param>
+ 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, bool aggressiveMemoryOptimizations, CaseInsensitivePathCache relativePathCache)
: base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, isNamespaced: true, aggressiveMemoryOptimizations: aggressiveMemoryOptimizations)
{
this.GameContentManager = gameContentManager;
+ this.RelativePathCache = relativePathCache;
this.JsonHelper = jsonHelper;
this.ModName = modName;
@@ -88,101 +95,38 @@ namespace StardewModdingAPI.Framework.ContentManagers
if (this.Coordinator.TryParseManagedAssetKey(assetName.Name, out string contentManagerID, out IAssetName relativePath))
{
if (contentManagerID != this.Name)
- throw new SContentLoadException($"Can't load managed asset key '{assetName}' through content manager '{this.Name}' for a different mod.");
+ throw this.GetLoadError(assetName, "can't load a different mod's managed asset key through this mod content manager.");
assetName = relativePath;
}
}
// get local asset
- SContentLoadException GetContentError(string reasonPhrase) => new($"Failed loading asset '{assetName}' from {this.Name}: {reasonPhrase}");
T asset;
try
{
// get file
FileInfo file = this.GetModFile(assetName.Name);
if (!file.Exists)
- throw GetContentError("the specified path doesn't exist.");
+ throw this.GetLoadError(assetName, "the specified path doesn't exist.");
// load content
- switch (file.Extension.ToLower())
+ asset = file.Extension.ToLower() switch
{
- // XNB file
- case ".xnb":
- {
- // the underlying content manager adds a .xnb extension implicitly, so
- // we need to strip it here to avoid trying to load a '.xnb.xnb' file.
- IAssetName loadName = this.Coordinator.ParseAssetName(assetName.Name[..^".xnb".Length]);
-
- // load asset
- asset = this.RawLoad<T>(loadName, useCache: false);
- if (asset is Map map)
- {
- map.assetPath = loadName.Name;
- this.FixTilesheetPaths(map, relativeMapPath: loadName.Name, fixEagerPathPrefixes: true);
- }
- }
- break;
-
- // unpacked Bitmap font
- case ".fnt":
- {
- string source = File.ReadAllText(file.FullName);
- asset = (T)(object)new XmlSource(source);
- }
- break;
-
- // unpacked data
- case ".json":
- {
- if (!this.JsonHelper.ReadJsonFileIfExists(file.FullName, out asset))
- throw GetContentError("the JSON file is invalid."); // should never happen since we check for file existence above
- }
- break;
-
- // unpacked image
- case ".png":
- {
- // validate
- if (typeof(T) != typeof(Texture2D))
- throw GetContentError($"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(Texture2D)}'.");
-
- // fetch & cache
- using FileStream stream = File.OpenRead(file.FullName);
-
- Texture2D texture = Texture2D.FromStream(Game1.graphics.GraphicsDevice, stream);
- texture = this.PremultiplyTransparency(texture);
- asset = (T)(object)texture;
- }
- break;
-
- // unpacked map
- case ".tbin":
- case ".tmx":
- {
- // validate
- if (typeof(T) != typeof(Map))
- throw GetContentError($"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(Map)}'.");
-
- // fetch & cache
- FormatManager formatManager = FormatManager.Instance;
- Map map = formatManager.LoadMap(file.FullName);
- map.assetPath = assetName.Name;
- this.FixTilesheetPaths(map, relativeMapPath: assetName.Name, fixEagerPathPrefixes: false);
- asset = (T)(object)map;
- }
- break;
-
- default:
- throw GetContentError($"unknown file extension '{file.Extension}'; must be one of '.fnt', '.json', '.png', '.tbin', or '.xnb'.");
- }
+ ".fnt" => this.LoadFont<T>(assetName, file),
+ ".json" => this.LoadDataFile<T>(assetName, file),
+ ".png" => this.LoadImageFile<T>(assetName, file),
+ ".tbin" or ".tmx" => this.LoadMapFile<T>(assetName, file),
+ ".xnb" => this.LoadXnbFile<T>(assetName),
+ _ => this.HandleUnknownFileType<T>(assetName, file)
+ };
}
- catch (Exception ex) when (!(ex is SContentLoadException))
+ catch (Exception ex) when (ex is not SContentLoadException)
{
- throw new SContentLoadException($"The content manager failed loading content asset '{assetName}' from {this.Name}.", ex);
+ throw this.GetLoadError(assetName, "an unexpected occurred.", ex);
}
// track & return asset
- this.TrackAsset(assetName, asset, useCache);
+ this.TrackAsset(assetName, asset, useCache: false);
return asset;
}
@@ -198,20 +142,125 @@ namespace StardewModdingAPI.Framework.ContentManagers
public IAssetName GetInternalAssetKey(string key)
{
FileInfo file = this.GetModFile(key);
- string relativePath = PathUtilities.GetRelativePath(this.RootDirectory, file.FullName);
+ string relativePath = Path.GetRelativePath(this.RootDirectory, file.FullName);
string internalKey = Path.Combine(this.Name, relativePath);
- return this.Coordinator.ParseAssetName(internalKey);
+ return this.Coordinator.ParseAssetName(internalKey, allowLocales: false);
}
/*********
** Private methods
*********/
+ /// <summary>Load an unpacked font file (<c>.fnt</c>).</summary>
+ /// <typeparam name="T">The type of asset to load.</typeparam>
+ /// <param name="assetName">The asset name relative to the loader root directory.</param>
+ /// <param name="file">The file to load.</param>
+ private T LoadFont<T>(IAssetName assetName, FileInfo file)
+ {
+ // validate
+ if (!typeof(T).IsAssignableFrom(typeof(XmlSource)))
+ throw this.GetLoadError(assetName, $"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(XmlSource)}'.");
+
+ // load
+ string source = File.ReadAllText(file.FullName);
+ return (T)(object)new XmlSource(source);
+ }
+
+ /// <summary>Load an unpacked data file (<c>.json</c>).</summary>
+ /// <typeparam name="T">The type of asset to load.</typeparam>
+ /// <param name="assetName">The asset name relative to the loader root directory.</param>
+ /// <param name="file">The file to load.</param>
+ private T LoadDataFile<T>(IAssetName assetName, FileInfo file)
+ {
+ if (!this.JsonHelper.ReadJsonFileIfExists(file.FullName, out T asset))
+ throw this.GetLoadError(assetName, "the JSON file is invalid."); // should never happen since we check for file existence before calling this method
+
+ return asset;
+ }
+
+ /// <summary>Load an unpacked image file (<c>.json</c>).</summary>
+ /// <typeparam name="T">The type of asset to load.</typeparam>
+ /// <param name="assetName">The asset name relative to the loader root directory.</param>
+ /// <param name="file">The file to load.</param>
+ private T LoadImageFile<T>(IAssetName assetName, FileInfo file)
+ {
+ // validate
+ if (typeof(T) != typeof(Texture2D))
+ throw this.GetLoadError(assetName, $"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(Texture2D)}'.");
+
+ // load
+ using FileStream stream = File.OpenRead(file.FullName);
+ Texture2D texture = Texture2D.FromStream(Game1.graphics.GraphicsDevice, stream);
+ texture = this.PremultiplyTransparency(texture);
+ return (T)(object)texture;
+ }
+
+ /// <summary>Load an unpacked image file (<c>.tbin</c> or <c>.tmx</c>).</summary>
+ /// <typeparam name="T">The type of asset to load.</typeparam>
+ /// <param name="assetName">The asset name relative to the loader root directory.</param>
+ /// <param name="file">The file to load.</param>
+ private T LoadMapFile<T>(IAssetName assetName, FileInfo file)
+ {
+ // validate
+ if (typeof(T) != typeof(Map))
+ throw this.GetLoadError(assetName, $"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(Map)}'.");
+
+ // load
+ FormatManager formatManager = FormatManager.Instance;
+ Map map = formatManager.LoadMap(file.FullName);
+ map.assetPath = assetName.Name;
+ this.FixTilesheetPaths(map, relativeMapPath: assetName.Name, fixEagerPathPrefixes: false);
+ return (T)(object)map;
+ }
+
+ /// <summary>Load a packed file (<c>.xnb</c>).</summary>
+ /// <typeparam name="T">The type of asset to load.</typeparam>
+ /// <param name="assetName">The asset name relative to the loader root directory.</param>
+ private T LoadXnbFile<T>(IAssetName assetName)
+ {
+ // the underlying content manager adds a .xnb extension implicitly, so
+ // we need to strip it here to avoid trying to load a '.xnb.xnb' file.
+ IAssetName loadName = assetName.Name.EndsWith(".xnb", StringComparison.OrdinalIgnoreCase)
+ ? this.Coordinator.ParseAssetName(assetName.Name[..^".xnb".Length], allowLocales: false)
+ : assetName;
+
+ // load asset
+ T asset = this.RawLoad<T>(loadName, useCache: false);
+ if (asset is Map map)
+ {
+ map.assetPath = loadName.Name;
+ this.FixTilesheetPaths(map, relativeMapPath: loadName.Name, fixEagerPathPrefixes: true);
+ }
+
+ return asset;
+ }
+
+ /// <summary>Handle a request to load a file type that isn't supported by SMAPI.</summary>
+ /// <typeparam name="T">The expected file type.</typeparam>
+ /// <param name="assetName">The asset name relative to the loader root directory.</param>
+ /// <param name="file">The file to load.</param>
+ private T HandleUnknownFileType<T>(IAssetName assetName, FileInfo file)
+ {
+ throw this.GetLoadError(assetName, $"unknown file extension '{file.Extension}'; must be one of '.fnt', '.json', '.png', '.tbin', '.tmx', or '.xnb'.");
+ }
+
+ /// <summary>Get an error which indicates that an asset couldn't be loaded.</summary>
+ /// <param name="assetName">The asset name that failed to load.</param>
+ /// <param name="reasonPhrase">The reason the file couldn't be loaded.</param>
+ /// <param name="exception">The underlying exception, if applicable.</param>
+ private SContentLoadException GetLoadError(IAssetName assetName, string reasonPhrase, Exception exception = null)
+ {
+ return new($"Failed loading asset '{assetName}' from {this.Name}: {reasonPhrase}", exception);
+ }
+
/// <summary>Get a file from the mod folder.</summary>
/// <param name="path">The asset path relative to the content folder.</param>
private FileInfo GetModFile(string path)
{
+ // map to case-insensitive path if needed
+ path = this.RelativePathCache.GetFilePath(path);
+
// try exact match
FileInfo file = new(Path.Combine(this.FullRootDirectory, path));
@@ -343,7 +392,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
}
// get from game assets
- IAssetName contentKey = this.Coordinator.ParseAssetName(this.GetContentKeyForTilesheetImageSource(relativePath));
+ IAssetName contentKey = this.Coordinator.ParseAssetName(this.GetContentKeyForTilesheetImageSource(relativePath), allowLocales: false);
try
{
this.GameContentManager.LoadLocalized<Texture2D>(contentKey, this.GameContentManager.Language, useCache: true); // no need to bypass cache here, since we're not storing the asset
diff --git a/src/SMAPI/Framework/ContentPack.cs b/src/SMAPI/Framework/ContentPack.cs
index 3920354e..2d33a22e 100644
--- a/src/SMAPI/Framework/ContentPack.cs
+++ b/src/SMAPI/Framework/ContentPack.cs
@@ -1,9 +1,10 @@
+#nullable disable
+
using System;
-using System.Collections.Generic;
using System.IO;
using StardewModdingAPI.Framework.ModHelpers;
using StardewModdingAPI.Toolkit.Serialization;
-using StardewModdingAPI.Toolkit.Utilities;
+using StardewModdingAPI.Utilities;
namespace StardewModdingAPI.Framework
{
@@ -16,8 +17,8 @@ namespace StardewModdingAPI.Framework
/// <summary>Encapsulates SMAPI's JSON file parsing.</summary>
private readonly JsonHelper JsonHelper;
- /// <summary>A cache of case-insensitive => exact relative paths within the content pack, for case-insensitive file lookups on Linux/macOS.</summary>
- private readonly IDictionary<string, string> RelativePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ /// <summary>A case-insensitive lookup of relative paths within the <see cref="DirectoryPath"/>.</summary>
+ private readonly CaseInsensitivePathCache RelativePathCache;
/*********
@@ -48,19 +49,15 @@ namespace StardewModdingAPI.Framework
/// <param name="content">Provides an API for loading content assets from the content pack's folder.</param>
/// <param name="translation">Provides translations stored in the content pack's <c>i18n</c> folder.</param>
/// <param name="jsonHelper">Encapsulates SMAPI's JSON file parsing.</param>
- public ContentPack(string directoryPath, IManifest manifest, IModContentHelper content, TranslationHelper translation, JsonHelper jsonHelper)
+ /// <param name="relativePathCache">A case-insensitive lookup of relative paths within the <paramref name="directoryPath"/>.</param>
+ public ContentPack(string directoryPath, IManifest manifest, IModContentHelper content, TranslationHelper translation, JsonHelper jsonHelper, CaseInsensitivePathCache relativePathCache)
{
this.DirectoryPath = directoryPath;
this.Manifest = manifest;
this.ModContent = content;
this.TranslationImpl = translation;
this.JsonHelper = jsonHelper;
-
- foreach (string path in Directory.EnumerateFiles(this.DirectoryPath, "*", SearchOption.AllDirectories))
- {
- string relativePath = path.Substring(this.DirectoryPath.Length + 1);
- this.RelativePaths[relativePath] = relativePath;
- }
+ this.RelativePathCache = relativePathCache;
}
/// <inheritdoc />
@@ -90,8 +87,7 @@ namespace StardewModdingAPI.Framework
FileInfo file = this.GetFile(path, out path);
this.JsonHelper.WriteJsonFile(file.FullName, data);
- if (!this.RelativePaths.ContainsKey(path))
- this.RelativePaths[path] = path;
+ this.RelativePathCache.Add(path);
}
/// <inheritdoc />
@@ -112,18 +108,6 @@ namespace StardewModdingAPI.Framework
/*********
** Private methods
*********/
- /// <summary>Get the real relative path from a case-insensitive path.</summary>
- /// <param name="relativePath">The normalized relative path.</param>
- private string GetCaseInsensitiveRelativePath(string relativePath)
- {
- if (!PathUtilities.IsSafeRelativePath(relativePath))
- throw new InvalidOperationException($"You must call {nameof(IContentPack)} methods with a relative path.");
-
- return !string.IsNullOrWhiteSpace(relativePath) && this.RelativePaths.TryGetValue(relativePath, out string caseInsensitivePath)
- ? caseInsensitivePath
- : relativePath;
- }
-
/// <summary>Get the underlying file info.</summary>
/// <param name="relativePath">The normalized file path relative to the content pack directory.</param>
private FileInfo GetFile(string relativePath)
@@ -136,7 +120,11 @@ namespace StardewModdingAPI.Framework
/// <param name="actualRelativePath">The relative path after case-insensitive matching.</param>
private FileInfo GetFile(string relativePath, out string actualRelativePath)
{
- actualRelativePath = this.GetCaseInsensitiveRelativePath(relativePath);
+ if (!PathUtilities.IsSafeRelativePath(relativePath))
+ throw new InvalidOperationException($"You must call {nameof(IContentPack)} methods with a relative path.");
+
+ actualRelativePath = this.RelativePathCache.GetFilePath(relativePath);
+
return new FileInfo(Path.Combine(this.DirectoryPath, actualRelativePath));
}
}
diff --git a/src/SMAPI/Framework/CursorPosition.cs b/src/SMAPI/Framework/CursorPosition.cs
index 107481e7..8f36a554 100644
--- a/src/SMAPI/Framework/CursorPosition.cs
+++ b/src/SMAPI/Framework/CursorPosition.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using Microsoft.Xna.Framework;
using StardewValley;
diff --git a/src/SMAPI/Framework/DeprecationManager.cs b/src/SMAPI/Framework/DeprecationManager.cs
index fc1b434b..fe1b623f 100644
--- a/src/SMAPI/Framework/DeprecationManager.cs
+++ b/src/SMAPI/Framework/DeprecationManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -11,7 +13,7 @@ namespace StardewModdingAPI.Framework
** Fields
*********/
/// <summary>The deprecations which have already been logged (as 'mod name::noun phrase::version').</summary>
- private readonly HashSet<string> LoggedDeprecations = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
+ private readonly HashSet<string> LoggedDeprecations = new(StringComparer.OrdinalIgnoreCase);
/// <summary>Encapsulates monitoring and logging for a given module.</summary>
private readonly IMonitor Monitor;
diff --git a/src/SMAPI/Framework/DeprecationWarning.cs b/src/SMAPI/Framework/DeprecationWarning.cs
index 5201b06c..f155358b 100644
--- a/src/SMAPI/Framework/DeprecationWarning.cs
+++ b/src/SMAPI/Framework/DeprecationWarning.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI.Framework
{
/// <summary>A deprecation warning for a mod.</summary>
diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs
index 41540047..c977e73d 100644
--- a/src/SMAPI/Framework/Events/EventManager.cs
+++ b/src/SMAPI/Framework/Events/EventManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using StardewModdingAPI.Events;
namespace StardewModdingAPI.Framework.Events
diff --git a/src/SMAPI/Framework/Events/IManagedEvent.cs b/src/SMAPI/Framework/Events/IManagedEvent.cs
index e4e3ca08..57277576 100644
--- a/src/SMAPI/Framework/Events/IManagedEvent.cs
+++ b/src/SMAPI/Framework/Events/IManagedEvent.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI.Framework.Events
{
/// <summary>Metadata for an event raised by SMAPI.</summary>
diff --git a/src/SMAPI/Framework/Events/ManagedEvent.cs b/src/SMAPI/Framework/Events/ManagedEvent.cs
index 154ef659..8fa31165 100644
--- a/src/SMAPI/Framework/Events/ManagedEvent.cs
+++ b/src/SMAPI/Framework/Events/ManagedEvent.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -18,7 +20,7 @@ namespace StardewModdingAPI.Framework.Events
protected readonly ModRegistry ModRegistry;
/// <summary>The underlying event handlers.</summary>
- private readonly List<ManagedEventHandler<TEventArgs>> Handlers = new List<ManagedEventHandler<TEventArgs>>();
+ private readonly List<ManagedEventHandler<TEventArgs>> Handlers = new();
/// <summary>A cached snapshot of <see cref="Handlers"/>, or <c>null</c> to rebuild it next raise.</summary>
private ManagedEventHandler<TEventArgs>[] CachedHandlers = Array.Empty<ManagedEventHandler<TEventArgs>>();
diff --git a/src/SMAPI/Framework/Events/ManagedEventHandler.cs b/src/SMAPI/Framework/Events/ManagedEventHandler.cs
index 28e88be0..f31bc04d 100644
--- a/src/SMAPI/Framework/Events/ManagedEventHandler.cs
+++ b/src/SMAPI/Framework/Events/ManagedEventHandler.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Events;
@@ -42,7 +44,7 @@ namespace StardewModdingAPI.Framework.Events
/// <inheritdoc />
public int CompareTo(object obj)
{
- if (!(obj is ManagedEventHandler<TEventArgs> other))
+ if (obj is not ManagedEventHandler<TEventArgs> other)
throw new ArgumentException("Can't compare to an unrelated object type.");
int priorityCompare = -this.Priority.CompareTo(other.Priority); // higher value = sort first
diff --git a/src/SMAPI/Framework/Events/ModContentEvents.cs b/src/SMAPI/Framework/Events/ModContentEvents.cs
index beb96031..f198b793 100644
--- a/src/SMAPI/Framework/Events/ModContentEvents.cs
+++ b/src/SMAPI/Framework/Events/ModContentEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Events;
diff --git a/src/SMAPI/Framework/Events/ModDisplayEvents.cs b/src/SMAPI/Framework/Events/ModDisplayEvents.cs
index 48f55324..b2110cce 100644
--- a/src/SMAPI/Framework/Events/ModDisplayEvents.cs
+++ b/src/SMAPI/Framework/Events/ModDisplayEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Events;
diff --git a/src/SMAPI/Framework/Events/ModEvents.cs b/src/SMAPI/Framework/Events/ModEvents.cs
index 1fb3482c..e8f8885d 100644
--- a/src/SMAPI/Framework/Events/ModEvents.cs
+++ b/src/SMAPI/Framework/Events/ModEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using StardewModdingAPI.Events;
namespace StardewModdingAPI.Framework.Events
diff --git a/src/SMAPI/Framework/Events/ModEventsBase.cs b/src/SMAPI/Framework/Events/ModEventsBase.cs
index 77708fc1..295caa0d 100644
--- a/src/SMAPI/Framework/Events/ModEventsBase.cs
+++ b/src/SMAPI/Framework/Events/ModEventsBase.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI.Framework.Events
{
/// <summary>An internal base class for event API classes.</summary>
diff --git a/src/SMAPI/Framework/Events/ModGameLoopEvents.cs b/src/SMAPI/Framework/Events/ModGameLoopEvents.cs
index 5f0db369..51803daf 100644
--- a/src/SMAPI/Framework/Events/ModGameLoopEvents.cs
+++ b/src/SMAPI/Framework/Events/ModGameLoopEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Events;
diff --git a/src/SMAPI/Framework/Events/ModInputEvents.cs b/src/SMAPI/Framework/Events/ModInputEvents.cs
index 40edf806..6af79c59 100644
--- a/src/SMAPI/Framework/Events/ModInputEvents.cs
+++ b/src/SMAPI/Framework/Events/ModInputEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Events;
diff --git a/src/SMAPI/Framework/Events/ModMultiplayerEvents.cs b/src/SMAPI/Framework/Events/ModMultiplayerEvents.cs
index b90f64fa..7d3ce510 100644
--- a/src/SMAPI/Framework/Events/ModMultiplayerEvents.cs
+++ b/src/SMAPI/Framework/Events/ModMultiplayerEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Events;
diff --git a/src/SMAPI/Framework/Events/ModPlayerEvents.cs b/src/SMAPI/Framework/Events/ModPlayerEvents.cs
index b2d89e9a..dac8f05b 100644
--- a/src/SMAPI/Framework/Events/ModPlayerEvents.cs
+++ b/src/SMAPI/Framework/Events/ModPlayerEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Events;
diff --git a/src/SMAPI/Framework/Events/ModSpecialisedEvents.cs b/src/SMAPI/Framework/Events/ModSpecialisedEvents.cs
index 7980208b..4b438034 100644
--- a/src/SMAPI/Framework/Events/ModSpecialisedEvents.cs
+++ b/src/SMAPI/Framework/Events/ModSpecialisedEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Events;
diff --git a/src/SMAPI/Framework/Events/ModWorldEvents.cs b/src/SMAPI/Framework/Events/ModWorldEvents.cs
index a7b7d799..614945c7 100644
--- a/src/SMAPI/Framework/Events/ModWorldEvents.cs
+++ b/src/SMAPI/Framework/Events/ModWorldEvents.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Events;
diff --git a/src/SMAPI/Framework/Exceptions/SAssemblyLoadFailedException.cs b/src/SMAPI/Framework/Exceptions/SAssemblyLoadFailedException.cs
index ec9279f1..4e03a687 100644
--- a/src/SMAPI/Framework/Exceptions/SAssemblyLoadFailedException.cs
+++ b/src/SMAPI/Framework/Exceptions/SAssemblyLoadFailedException.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Framework.Exceptions
diff --git a/src/SMAPI/Framework/Exceptions/SContentLoadException.cs b/src/SMAPI/Framework/Exceptions/SContentLoadException.cs
index 85d85e3d..c21a6b0e 100644
--- a/src/SMAPI/Framework/Exceptions/SContentLoadException.cs
+++ b/src/SMAPI/Framework/Exceptions/SContentLoadException.cs
@@ -1,4 +1,6 @@
-using System;
+#nullable disable
+
+using System;
using Microsoft.Xna.Framework.Content;
namespace StardewModdingAPI.Framework.Exceptions
diff --git a/src/SMAPI/Framework/GameVersion.cs b/src/SMAPI/Framework/GameVersion.cs
index b69c6757..aa91d8f3 100644
--- a/src/SMAPI/Framework/GameVersion.cs
+++ b/src/SMAPI/Framework/GameVersion.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
diff --git a/src/SMAPI/Framework/IModMetadata.cs b/src/SMAPI/Framework/IModMetadata.cs
index cb876ee4..800b198a 100644
--- a/src/SMAPI/Framework/IModMetadata.cs
+++ b/src/SMAPI/Framework/IModMetadata.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using StardewModdingAPI.Framework.ModHelpers;
diff --git a/src/SMAPI/Framework/Input/GamePadStateBuilder.cs b/src/SMAPI/Framework/Input/GamePadStateBuilder.cs
index ad254828..21168b7a 100644
--- a/src/SMAPI/Framework/Input/GamePadStateBuilder.cs
+++ b/src/SMAPI/Framework/Input/GamePadStateBuilder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
diff --git a/src/SMAPI/Framework/Input/IInputStateBuilder.cs b/src/SMAPI/Framework/Input/IInputStateBuilder.cs
index 28d62439..3fb62686 100644
--- a/src/SMAPI/Framework/Input/IInputStateBuilder.cs
+++ b/src/SMAPI/Framework/Input/IInputStateBuilder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
namespace StardewModdingAPI.Framework.Input
diff --git a/src/SMAPI/Framework/Input/KeyboardStateBuilder.cs b/src/SMAPI/Framework/Input/KeyboardStateBuilder.cs
index eadb7a8a..81ca0ebb 100644
--- a/src/SMAPI/Framework/Input/KeyboardStateBuilder.cs
+++ b/src/SMAPI/Framework/Input/KeyboardStateBuilder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework.Input;
@@ -14,7 +16,7 @@ namespace StardewModdingAPI.Framework.Input
private KeyboardState? State;
/// <summary>The pressed buttons.</summary>
- private readonly HashSet<Keys> PressedButtons = new HashSet<Keys>();
+ private readonly HashSet<Keys> PressedButtons = new();
/*********
diff --git a/src/SMAPI/Framework/Input/MouseStateBuilder.cs b/src/SMAPI/Framework/Input/MouseStateBuilder.cs
index c2a0891b..85b38d32 100644
--- a/src/SMAPI/Framework/Input/MouseStateBuilder.cs
+++ b/src/SMAPI/Framework/Input/MouseStateBuilder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using Microsoft.Xna.Framework.Input;
diff --git a/src/SMAPI/Framework/Input/SInputState.cs b/src/SMAPI/Framework/Input/SInputState.cs
index a8d1f371..37b3c8ef 100644
--- a/src/SMAPI/Framework/Input/SInputState.cs
+++ b/src/SMAPI/Framework/Input/SInputState.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -21,10 +23,10 @@ namespace StardewModdingAPI.Framework.Input
private Vector2? LastPlayerTile;
/// <summary>The buttons to press until the game next handles input.</summary>
- private readonly HashSet<SButton> CustomPressedKeys = new HashSet<SButton>();
+ private readonly HashSet<SButton> CustomPressedKeys = new();
/// <summary>The buttons to consider released until the actual button is released.</summary>
- private readonly HashSet<SButton> CustomReleasedKeys = new HashSet<SButton>();
+ private readonly HashSet<SButton> CustomReleasedKeys = new();
/// <summary>Whether there are new overrides in <see cref="CustomPressedKeys"/> or <see cref="CustomReleasedKeys"/> that haven't been applied to the previous state.</summary>
private bool HasNewOverrides;
@@ -72,8 +74,8 @@ namespace StardewModdingAPI.Framework.Input
var controller = new GamePadStateBuilder(base.GetGamePadState());
var keyboard = new KeyboardStateBuilder(base.GetKeyboardState());
var mouse = new MouseStateBuilder(base.GetMouseState());
- Vector2 cursorAbsolutePos = new Vector2((mouse.X * zoomMultiplier) + Game1.viewport.X, (mouse.Y * zoomMultiplier) + Game1.viewport.Y);
- Vector2? playerTilePos = Context.IsPlayerFree ? Game1.player.getTileLocation() : (Vector2?)null;
+ Vector2 cursorAbsolutePos = new((mouse.X * zoomMultiplier) + Game1.viewport.X, (mouse.Y * zoomMultiplier) + Game1.viewport.Y);
+ Vector2? playerTilePos = Context.IsPlayerFree ? Game1.player.getTileLocation() : null;
HashSet<SButton> reallyDown = new HashSet<SButton>(this.GetPressedButtons(keyboard, mouse, controller));
// apply overrides
@@ -203,8 +205,8 @@ namespace StardewModdingAPI.Framework.Input
/// <param name="zoomMultiplier">The multiplier applied to pixel coordinates to adjust them for pixel zoom.</param>
private CursorPosition GetCursorPosition(MouseState mouseState, Vector2 absolutePixels, float zoomMultiplier)
{
- Vector2 screenPixels = new Vector2(mouseState.X * zoomMultiplier, mouseState.Y * zoomMultiplier);
- Vector2 tile = new Vector2((int)((Game1.viewport.X + screenPixels.X) / Game1.tileSize), (int)((Game1.viewport.Y + screenPixels.Y) / Game1.tileSize));
+ Vector2 screenPixels = new(mouseState.X * zoomMultiplier, mouseState.Y * zoomMultiplier);
+ Vector2 tile = new((int)((Game1.viewport.X + screenPixels.X) / Game1.tileSize), (int)((Game1.viewport.Y + screenPixels.Y) / Game1.tileSize));
Vector2 grabTile = (Game1.mouseCursorTransparency > 0 && Utility.tileWithinRadiusOfPlayer((int)tile.X, (int)tile.Y, 1, Game1.player)) // derived from Game1.pressActionButton
? tile
: Game1.player.GetGrabTile();
@@ -234,7 +236,7 @@ namespace StardewModdingAPI.Framework.Input
isDown: pressed.Contains(button)
);
- if (button == SButton.MouseLeft || button == SButton.MouseMiddle || button == SButton.MouseRight || button == SButton.MouseX1 || button == SButton.MouseX2)
+ if (button is SButton.MouseLeft or SButton.MouseMiddle or SButton.MouseRight or SButton.MouseX1 or SButton.MouseX2)
mouseOverrides[button] = newState;
else if (button.TryGetKeyboard(out Keys _))
keyboardOverrides[button] = newState;
diff --git a/src/SMAPI/Framework/InternalExtensions.cs b/src/SMAPI/Framework/InternalExtensions.cs
index fe10b045..a1d87487 100644
--- a/src/SMAPI/Framework/InternalExtensions.cs
+++ b/src/SMAPI/Framework/InternalExtensions.cs
@@ -1,7 +1,8 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Reflection;
using System.Threading;
using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI.Framework.Events;
diff --git a/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs b/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs
index bad69a2a..a0957b90 100644
--- a/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs
+++ b/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.IO;
using System.Text;
diff --git a/src/SMAPI/Framework/Logging/LogFileManager.cs b/src/SMAPI/Framework/Logging/LogFileManager.cs
index 6ab2bdfb..0b6f9ad2 100644
--- a/src/SMAPI/Framework/Logging/LogFileManager.cs
+++ b/src/SMAPI/Framework/Logging/LogFileManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.IO;
diff --git a/src/SMAPI/Framework/Logging/LogManager.cs b/src/SMAPI/Framework/Logging/LogManager.cs
index a8a8b6ee..dab7f554 100644
--- a/src/SMAPI/Framework/Logging/LogManager.cs
+++ b/src/SMAPI/Framework/Logging/LogManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
diff --git a/src/SMAPI/Framework/ModHelpers/BaseHelper.cs b/src/SMAPI/Framework/ModHelpers/BaseHelper.cs
index 5a3d4bed..1cd1a6b3 100644
--- a/src/SMAPI/Framework/ModHelpers/BaseHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/BaseHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI.Framework.ModHelpers
{
/// <summary>The common base class for mod helpers.</summary>
diff --git a/src/SMAPI/Framework/ModHelpers/CommandHelper.cs b/src/SMAPI/Framework/ModHelpers/CommandHelper.cs
index 69382009..c2b5092e 100644
--- a/src/SMAPI/Framework/ModHelpers/CommandHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/CommandHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Framework.ModHelpers
diff --git a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs
index b0064532..e72e397e 100644
--- a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -107,7 +109,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <inheritdoc />
public T Load<T>(string key, ContentSource source = ContentSource.ModFolder)
{
- IAssetName assetName = this.ContentCore.ParseAssetName(key);
+ IAssetName assetName = this.ContentCore.ParseAssetName(key, allowLocales: source == ContentSource.GameContent);
try
{
@@ -124,7 +126,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
throw new SContentLoadException($"{this.ModName} failed loading content asset '{key}' from {source}: unknown content source '{source}'.");
}
}
- catch (Exception ex) when (!(ex is SContentLoadException))
+ catch (Exception ex) when (ex is not SContentLoadException)
{
throw new SContentLoadException($"{this.ModName} failed loading content asset '{key}' from {source}.", ex);
}
@@ -157,21 +159,21 @@ namespace StardewModdingAPI.Framework.ModHelpers
public bool InvalidateCache(string key)
{
string actualKey = this.GetActualAssetKey(key, ContentSource.GameContent);
- this.Monitor.Log($"Requested cache invalidation for '{actualKey}'.", LogLevel.Trace);
+ this.Monitor.Log($"Requested cache invalidation for '{actualKey}'.");
return this.ContentCore.InvalidateCache(asset => asset.Name.IsEquivalentTo(actualKey)).Any();
}
/// <inheritdoc />
public bool InvalidateCache<T>()
{
- this.Monitor.Log($"Requested cache invalidation for all assets of type {typeof(T)}. This is an expensive operation and should be avoided if possible.", LogLevel.Trace);
- return this.ContentCore.InvalidateCache((contentManager, key, type) => typeof(T).IsAssignableFrom(type)).Any();
+ this.Monitor.Log($"Requested cache invalidation for all assets of type {typeof(T)}. This is an expensive operation and should be avoided if possible.");
+ return this.ContentCore.InvalidateCache((_, _, type) => typeof(T).IsAssignableFrom(type)).Any();
}
/// <inheritdoc />
public bool InvalidateCache(Func<IAssetInfo, bool> predicate)
{
- this.Monitor.Log("Requested cache invalidation for all assets matching a predicate.", LogLevel.Trace);
+ this.Monitor.Log("Requested cache invalidation for all assets matching a predicate.");
return this.ContentCore.InvalidateCache(predicate).Any();
}
@@ -183,7 +185,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
assetName ??= $"temp/{Guid.NewGuid():N}";
- return new AssetDataForObject(this.CurrentLocale, this.ContentCore.ParseAssetName(assetName), data, this.NormalizeAssetName);
+ return new AssetDataForObject(this.CurrentLocale, this.ContentCore.ParseAssetName(assetName, allowLocales: true/* no way to know if it's a game or mod asset here*/), data, this.NormalizeAssetName);
}
diff --git a/src/SMAPI/Framework/ModHelpers/ContentPackHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentPackHelper.cs
index d39abc7d..336214e2 100644
--- a/src/SMAPI/Framework/ModHelpers/ContentPackHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ContentPackHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.IO;
diff --git a/src/SMAPI/Framework/ModHelpers/DataHelper.cs b/src/SMAPI/Framework/ModHelpers/DataHelper.cs
index 4cbfd73f..86a34ee8 100644
--- a/src/SMAPI/Framework/ModHelpers/DataHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/DataHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.IO;
diff --git a/src/SMAPI/Framework/ModHelpers/GameContentHelper.cs b/src/SMAPI/Framework/ModHelpers/GameContentHelper.cs
index 42a4de20..956bac7f 100644
--- a/src/SMAPI/Framework/ModHelpers/GameContentHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/GameContentHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Linq;
using StardewModdingAPI.Framework.Content;
@@ -58,13 +60,13 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <inheritdoc />
public IAssetName ParseAssetName(string rawName)
{
- return this.ContentCore.ParseAssetName(rawName);
+ return this.ContentCore.ParseAssetName(rawName, allowLocales: true);
}
/// <inheritdoc />
public T Load<T>(string key)
{
- IAssetName assetName = this.ContentCore.ParseAssetName(key);
+ IAssetName assetName = this.ContentCore.ParseAssetName(key, allowLocales: true);
return this.Load<T>(assetName);
}
@@ -73,7 +75,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
{
try
{
- return this.GameContentManager.LoadLocalized<T>(assetName, this.CurrentLocaleConstant, useCache: false);
+ return this.GameContentManager.LoadLocalized<T>(assetName, this.CurrentLocaleConstant, useCache: true);
}
catch (Exception ex) when (ex is not SContentLoadException)
{
@@ -117,7 +119,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
assetName ??= $"temp/{Guid.NewGuid():N}";
- return new AssetDataForObject(this.CurrentLocale, this.ContentCore.ParseAssetName(assetName), data, key => this.ParseAssetName(key).Name);
+ return new AssetDataForObject(this.CurrentLocale, this.ContentCore.ParseAssetName(assetName, allowLocales: true), data, key => this.ParseAssetName(key).Name);
}
/// <summary>Get the underlying game content manager.</summary>
diff --git a/src/SMAPI/Framework/ModHelpers/InputHelper.cs b/src/SMAPI/Framework/ModHelpers/InputHelper.cs
index 88caf4c3..29f80d87 100644
--- a/src/SMAPI/Framework/ModHelpers/InputHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/InputHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Framework.Input;
using StardewModdingAPI.Utilities;
diff --git a/src/SMAPI/Framework/ModHelpers/ModContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ModContentHelper.cs
index 45899dd7..90064354 100644
--- a/src/SMAPI/Framework/ModHelpers/ModContentHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ModContentHelper.cs
@@ -1,7 +1,11 @@
+#nullable disable
+
using System;
+using Microsoft.Xna.Framework.Content;
using StardewModdingAPI.Framework.Content;
using StardewModdingAPI.Framework.ContentManagers;
using StardewModdingAPI.Framework.Exceptions;
+using StardewModdingAPI.Utilities;
namespace StardewModdingAPI.Framework.ModHelpers
{
@@ -20,6 +24,9 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <summary>The friendly mod name for use in errors.</summary>
private readonly string ModName;
+ /// <summary>A case-insensitive lookup of relative paths within the <see cref="ContentManager.RootDirectory"/>.</summary>
+ private readonly CaseInsensitivePathCache RelativePathCache;
+
/*********
** Public methods
@@ -30,7 +37,8 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <param name="modID">The unique ID of the relevant mod.</param>
/// <param name="modName">The friendly mod name for use in errors.</param>
/// <param name="gameContentManager">The game content manager used for map tilesheets not provided by the mod.</param>
- public ModContentHelper(ContentCoordinator contentCore, string modFolderPath, string modID, string modName, IContentManager gameContentManager)
+ /// <param name="relativePathCache">A case-insensitive lookup of relative paths within the <paramref name="relativePathCache"/>.</param>
+ public ModContentHelper(ContentCoordinator contentCore, string modFolderPath, string modID, string modName, IContentManager gameContentManager, CaseInsensitivePathCache relativePathCache)
: base(modID)
{
string managedAssetPrefix = contentCore.GetManagedAssetPrefix(modID);
@@ -38,12 +46,15 @@ namespace StardewModdingAPI.Framework.ModHelpers
this.ContentCore = contentCore;
this.ModContentManager = contentCore.CreateModContentManager(managedAssetPrefix, modName, modFolderPath, gameContentManager);
this.ModName = modName;
+ this.RelativePathCache = relativePathCache;
}
/// <inheritdoc />
public T Load<T>(string relativePath)
{
- IAssetName assetName = this.ContentCore.ParseAssetName(relativePath);
+ relativePath = this.RelativePathCache.GetAssetName(relativePath);
+
+ IAssetName assetName = this.ContentCore.ParseAssetName(relativePath, allowLocales: false);
try
{
@@ -58,6 +69,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <inheritdoc />
public IAssetName GetInternalAssetName(string relativePath)
{
+ relativePath = this.RelativePathCache.GetAssetName(relativePath);
return this.ModContentManager.GetInternalAssetKey(relativePath);
}
@@ -67,9 +79,11 @@ namespace StardewModdingAPI.Framework.ModHelpers
if (data == null)
throw new ArgumentNullException(nameof(data), "Can't get a patch helper for a null value.");
- relativePath ??= $"temp/{Guid.NewGuid():N}";
+ relativePath = relativePath != null
+ ? this.RelativePathCache.GetAssetName(relativePath)
+ : $"temp/{Guid.NewGuid():N}";
- return new AssetDataForObject(this.ContentCore.GetLocale(), this.ContentCore.ParseAssetName(relativePath), data, key => this.ContentCore.ParseAssetName(key).Name);
+ return new AssetDataForObject(this.ContentCore.GetLocale(), this.ContentCore.ParseAssetName(relativePath, allowLocales: false), data, key => this.ContentCore.ParseAssetName(key, allowLocales: false).Name);
}
}
}
diff --git a/src/SMAPI/Framework/ModHelpers/ModHelper.cs b/src/SMAPI/Framework/ModHelpers/ModHelper.cs
index d28faacc..3cfe52bf 100644
--- a/src/SMAPI/Framework/ModHelpers/ModHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ModHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.IO;
using StardewModdingAPI.Events;
@@ -13,7 +15,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
*********/
/// <summary>The backing field for <see cref="Content"/>.</summary>
[Obsolete]
- private readonly IContentHelper ContentImpl;
+ private readonly ContentHelper ContentImpl;
/*********
@@ -93,7 +95,13 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <param name="translationHelper">An API for reading translations stored in the mod's <c>i18n</c> folder.</param>
/// <exception cref="ArgumentNullException">An argument is null or empty.</exception>
/// <exception cref="InvalidOperationException">The <paramref name="modDirectory"/> path does not exist on disk.</exception>
- public ModHelper(string modID, string modDirectory, Func<SInputState> currentInputState, IModEvents events, IContentHelper contentHelper, IGameContentHelper gameContentHelper, IModContentHelper modContentHelper, IContentPackHelper contentPackHelper, ICommandHelper commandHelper, IDataHelper dataHelper, IModRegistry modRegistry, IReflectionHelper reflectionHelper, IMultiplayerHelper multiplayer, ITranslationHelper translationHelper)
+ public ModHelper(
+ string modID, string modDirectory, Func<SInputState> currentInputState, IModEvents events,
+#pragma warning disable CS0612 // deprecated code
+ ContentHelper contentHelper,
+#pragma warning restore CS0612
+ IGameContentHelper gameContentHelper, IModContentHelper modContentHelper, IContentPackHelper contentPackHelper, ICommandHelper commandHelper, IDataHelper dataHelper, IModRegistry modRegistry, IReflectionHelper reflectionHelper, IMultiplayerHelper multiplayer, ITranslationHelper translationHelper
+ )
: base(modID)
{
// validate directory
@@ -104,7 +112,9 @@ namespace StardewModdingAPI.Framework.ModHelpers
// initialize
this.DirectoryPath = modDirectory;
+#pragma warning disable CS0612 // deprecated code
this.ContentImpl = contentHelper ?? throw new ArgumentNullException(nameof(contentHelper));
+#pragma warning restore CS0612
this.GameContent = gameContentHelper ?? throw new ArgumentNullException(nameof(gameContentHelper));
this.ModContent = modContentHelper ?? throw new ArgumentNullException(nameof(modContentHelper));
this.ContentPacks = contentPackHelper ?? throw new ArgumentNullException(nameof(contentPackHelper));
@@ -118,6 +128,13 @@ namespace StardewModdingAPI.Framework.ModHelpers
this.Events = events;
}
+ /// <summary>Get the underlying instance for <see cref="IContentHelper"/>.</summary>
+ [Obsolete]
+ public ContentHelper GetLegacyContentHelper()
+ {
+ return this.ContentImpl;
+ }
+
/****
** Mod config file
****/
diff --git a/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs b/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs
index 95eb03f3..e277e6fa 100644
--- a/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using StardewModdingAPI.Framework.Reflection;
@@ -69,7 +71,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
// get raw API
IModMetadata mod = this.Registry.Get(uniqueID);
if (mod?.Api != null && this.AccessedModApis.Add(mod.Manifest.UniqueID))
- this.Monitor.Log($"Accessed mod-provided API for {mod.DisplayName}.", LogLevel.Trace);
+ this.Monitor.Log($"Accessed mod-provided API for {mod.DisplayName}.");
return mod?.Api;
}
diff --git a/src/SMAPI/Framework/ModHelpers/MultiplayerHelper.cs b/src/SMAPI/Framework/ModHelpers/MultiplayerHelper.cs
index a7ce8692..96b074e2 100644
--- a/src/SMAPI/Framework/ModHelpers/MultiplayerHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/MultiplayerHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using StardewModdingAPI.Framework.Networking;
using StardewValley;
diff --git a/src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs b/src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs
index 5a4ea742..24cbd01c 100644
--- a/src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Reflection;
using StardewModdingAPI.Framework.Reflection;
diff --git a/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs b/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs
index 869664fe..37345a76 100644
--- a/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using StardewValley;
diff --git a/src/SMAPI/Framework/ModLinked.cs b/src/SMAPI/Framework/ModLinked.cs
index 8cfe6f5f..5a3e38ca 100644
--- a/src/SMAPI/Framework/ModLinked.cs
+++ b/src/SMAPI/Framework/ModLinked.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI.Framework
{
/// <summary>A generic tuple which links something to a mod.</summary>
diff --git a/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs b/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs
index 8e2f5ef3..1d4ddf72 100644
--- a/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs
+++ b/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using Mono.Cecil;
diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoadStatus.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoadStatus.cs
index 11be19fc..d2d5d83b 100644
--- a/src/SMAPI/Framework/ModLoading/AssemblyLoadStatus.cs
+++ b/src/SMAPI/Framework/ModLoading/AssemblyLoadStatus.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI.Framework.ModLoading
{
/// <summary>Indicates the result of an assembly load.</summary>
diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
index cb5fa2ae..070ee803 100644
--- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
+++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.IO;
@@ -36,13 +38,13 @@ namespace StardewModdingAPI.Framework.ModLoading
private readonly AssemblyDefinitionResolver AssemblyDefinitionResolver;
/// <summary>Provides assembly symbol readers for Mono.Cecil.</summary>
- private readonly SymbolReaderProvider SymbolReaderProvider = new SymbolReaderProvider();
+ private readonly SymbolReaderProvider SymbolReaderProvider = new();
/// <summary>Provides assembly symbol writers for Mono.Cecil.</summary>
- private readonly SymbolWriterProvider SymbolWriterProvider = new SymbolWriterProvider();
+ private readonly SymbolWriterProvider SymbolWriterProvider = new();
/// <summary>The objects to dispose as part of this instance.</summary>
- private readonly HashSet<IDisposable> Disposables = new HashSet<IDisposable>();
+ private readonly HashSet<IDisposable> Disposables = new();
/// <summary>Whether to rewrite mods for compatibility.</summary>
private readonly bool RewriteMods;
@@ -138,11 +140,11 @@ namespace StardewModdingAPI.Framework.ModLoading
if (changed)
{
if (!oneAssembly)
- this.Monitor.Log($" Loading {assembly.File.Name} (rewritten)...", LogLevel.Trace);
+ this.Monitor.Log($" Loading {assembly.File.Name} (rewritten)...");
// load assembly
- using MemoryStream outAssemblyStream = new MemoryStream();
- using MemoryStream outSymbolStream = new MemoryStream();
+ using MemoryStream outAssemblyStream = new();
+ using MemoryStream outSymbolStream = new();
assembly.Definition.Write(outAssemblyStream, new WriterParameters { WriteSymbols = true, SymbolStream = outSymbolStream, SymbolWriterProvider = this.SymbolWriterProvider });
byte[] bytes = outAssemblyStream.ToArray();
lastAssembly = Assembly.Load(bytes, outSymbolStream.ToArray());
@@ -150,7 +152,7 @@ namespace StardewModdingAPI.Framework.ModLoading
else
{
if (!oneAssembly)
- this.Monitor.Log($" Loading {assembly.File.Name}...", LogLevel.Trace);
+ this.Monitor.Log($" Loading {assembly.File.Name}...");
lastAssembly = Assembly.UnsafeLoadFrom(assembly.File.FullName);
}
@@ -241,7 +243,7 @@ namespace StardewModdingAPI.Framework.ModLoading
try
{
// read assembly with symbols
- FileInfo symbolsFile = new FileInfo(Path.Combine(Path.GetDirectoryName(file.FullName)!, Path.GetFileNameWithoutExtension(file.FullName)) + ".pdb");
+ FileInfo symbolsFile = new(Path.Combine(Path.GetDirectoryName(file.FullName)!, Path.GetFileNameWithoutExtension(file.FullName)) + ".pdb");
if (symbolsFile.Exists)
this.SymbolReaderProvider.TryAddSymbolData(file.Name, () => this.TrackForDisposal(symbolsFile.OpenRead()));
assembly = this.TrackForDisposal(AssemblyDefinition.ReadAssembly(readStream, new ReaderParameters(ReadingMode.Immediate) { AssemblyResolver = assemblyResolver, InMemory = true, ReadSymbols = true, SymbolReaderProvider = this.SymbolReaderProvider }));
@@ -266,7 +268,7 @@ namespace StardewModdingAPI.Framework.ModLoading
// yield referenced assemblies
foreach (AssemblyNameReference dependency in assembly.MainModule.AssemblyReferences)
{
- FileInfo dependencyFile = new FileInfo(Path.Combine(file.Directory.FullName, $"{dependency.Name}.dll"));
+ FileInfo dependencyFile = new(Path.Combine(file.Directory.FullName, $"{dependency.Name}.dll"));
foreach (AssemblyParseResult result in this.GetReferencedLocalAssemblies(dependencyFile, visitedAssemblyNames, assemblyResolver))
yield return result;
}
@@ -333,7 +335,7 @@ namespace StardewModdingAPI.Framework.ModLoading
// find or rewrite code
IInstructionHandler[] handlers = new InstructionMetadata().GetHandlers(this.ParanoidMode, platformChanged, this.RewriteMods).ToArray();
- RecursiveRewriter rewriter = new RecursiveRewriter(
+ RecursiveRewriter rewriter = new(
module: module,
rewriteModule: curModule =>
{
diff --git a/src/SMAPI/Framework/ModLoading/AssemblyParseResult.cs b/src/SMAPI/Framework/ModLoading/AssemblyParseResult.cs
index b56a776c..56bd5a8b 100644
--- a/src/SMAPI/Framework/ModLoading/AssemblyParseResult.cs
+++ b/src/SMAPI/Framework/ModLoading/AssemblyParseResult.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.IO;
using Mono.Cecil;
diff --git a/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs
index 124951a5..7c94beb7 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
diff --git a/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs
index 68415123..96b4098a 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
diff --git a/src/SMAPI/Framework/ModLoading/Finders/MethodFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/MethodFinder.cs
index d2340f01..7d3c1fd7 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/MethodFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/MethodFinder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using Mono.Cecil;
using Mono.Cecil.Cil;
using StardewModdingAPI.Framework.ModLoading.Framework;
diff --git a/src/SMAPI/Framework/ModLoading/Finders/PropertyFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/PropertyFinder.cs
index 99344848..b2f2e193 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/PropertyFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/PropertyFinder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using Mono.Cecil;
using Mono.Cecil.Cil;
using StardewModdingAPI.Framework.ModLoading.Framework;
diff --git a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs
index 8c1cae2b..81f90498 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
diff --git a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs
index d305daf4..001d1986 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Cil;
diff --git a/src/SMAPI/Framework/ModLoading/Finders/TypeAssemblyFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/TypeAssemblyFinder.cs
index 24ab2eca..4c589ed8 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/TypeAssemblyFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/TypeAssemblyFinder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Mono.Cecil;
using StardewModdingAPI.Framework.ModLoading.Framework;
diff --git a/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs
index 260a8df8..04a5b970 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using Mono.Cecil;
diff --git a/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs b/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs
index d5d1b38e..bea786cd 100644
--- a/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs
+++ b/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using Mono.Cecil;
diff --git a/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs b/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs
index 4f14a579..09ff78f7 100644
--- a/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs b/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs
index d7cb2471..8f47fbdd 100644
--- a/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs
+++ b/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Linq;
using System.Reflection;
diff --git a/src/SMAPI/Framework/ModLoading/IInstructionHandler.cs b/src/SMAPI/Framework/ModLoading/IInstructionHandler.cs
index d41732f8..126504e3 100644
--- a/src/SMAPI/Framework/ModLoading/IInstructionHandler.cs
+++ b/src/SMAPI/Framework/ModLoading/IInstructionHandler.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using Mono.Cecil;
diff --git a/src/SMAPI/Framework/ModLoading/IncompatibleInstructionException.cs b/src/SMAPI/Framework/ModLoading/IncompatibleInstructionException.cs
index 1f9add30..29406f2a 100644
--- a/src/SMAPI/Framework/ModLoading/IncompatibleInstructionException.cs
+++ b/src/SMAPI/Framework/ModLoading/IncompatibleInstructionException.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Framework.ModLoading
diff --git a/src/SMAPI/Framework/ModLoading/InvalidModStateException.cs b/src/SMAPI/Framework/ModLoading/InvalidModStateException.cs
index 075e237a..9dca9bc4 100644
--- a/src/SMAPI/Framework/ModLoading/InvalidModStateException.cs
+++ b/src/SMAPI/Framework/ModLoading/InvalidModStateException.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Framework.ModLoading
diff --git a/src/SMAPI/Framework/ModLoading/ModMetadata.cs b/src/SMAPI/Framework/ModLoading/ModMetadata.cs
index 9e6bc61f..0e698bfd 100644
--- a/src/SMAPI/Framework/ModLoading/ModMetadata.cs
+++ b/src/SMAPI/Framework/ModLoading/ModMetadata.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.IO;
diff --git a/src/SMAPI/Framework/ModLoading/ModResolver.cs b/src/SMAPI/Framework/ModLoading/ModResolver.cs
index 4b05d1e5..2842c11a 100644
--- a/src/SMAPI/Framework/ModLoading/ModResolver.cs
+++ b/src/SMAPI/Framework/ModLoading/ModResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.IO;
@@ -32,11 +34,8 @@ namespace StardewModdingAPI.Framework.ModLoading
ModDataRecordVersionedFields dataRecord = modDatabase.Get(manifest?.UniqueID)?.GetVersionedFields(manifest);
// apply defaults
- if (manifest != null && dataRecord != null)
- {
- if (dataRecord.UpdateKey != null)
- manifest.UpdateKeys = new[] { dataRecord.UpdateKey };
- }
+ if (manifest != null && dataRecord?.UpdateKey is not null)
+ manifest.OverrideUpdateKeys(dataRecord.UpdateKey);
// build metadata
bool shouldIgnore = folder.Type == ModType.Ignored;
@@ -240,7 +239,7 @@ namespace StardewModdingAPI.Framework.ModLoading
// initialize metadata
mods = mods.ToArray();
var sortedMods = new Stack<IModMetadata>();
- var states = mods.ToDictionary(mod => mod, mod => ModDependencyStatus.Queued);
+ var states = mods.ToDictionary(mod => mod, _ => ModDependencyStatus.Queued);
// handle failed mods
foreach (IModMetadata mod in mods.Where(m => m.Status == ModMetadataStatus.Failed))
@@ -401,7 +400,7 @@ namespace StardewModdingAPI.Framework.ModLoading
{
foreach (string modRootPath in Directory.GetDirectories(rootPath))
{
- DirectoryInfo directory = new DirectoryInfo(modRootPath);
+ DirectoryInfo directory = new(modRootPath);
// if a folder only contains another folder, check the inner folder instead
while (!directory.GetFiles().Any() && directory.GetDirectories().Length == 1)
diff --git a/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs b/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs
index d4366294..0898f095 100644
--- a/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs
+++ b/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/SMAPI/Framework/ModLoading/RewriteFacades/AccessToolsFacade.cs b/src/SMAPI/Framework/ModLoading/RewriteFacades/AccessToolsFacade.cs
index be2a1c58..c05005b8 100644
--- a/src/SMAPI/Framework/ModLoading/RewriteFacades/AccessToolsFacade.cs
+++ b/src/SMAPI/Framework/ModLoading/RewriteFacades/AccessToolsFacade.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
diff --git a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs
index 135bd218..fea8c100 100644
--- a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs
+++ b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
diff --git a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyMethodFacade.cs b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyMethodFacade.cs
index 5162dda4..93124591 100644
--- a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyMethodFacade.cs
+++ b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyMethodFacade.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
diff --git a/src/SMAPI/Framework/ModLoading/RewriteFacades/SpriteBatchFacade.cs b/src/SMAPI/Framework/ModLoading/RewriteFacades/SpriteBatchFacade.cs
index 5f68f8d9..20a30f8f 100644
--- a/src/SMAPI/Framework/ModLoading/RewriteFacades/SpriteBatchFacade.cs
+++ b/src/SMAPI/Framework/ModLoading/RewriteFacades/SpriteBatchFacade.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Diagnostics.CodeAnalysis;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs
index cc830216..4985d72a 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/ArchitectureAssemblyRewriter.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using Mono.Cecil;
using StardewModdingAPI.Framework.ModLoading.Framework;
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs
index 857a2230..806fca62 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Reflection;
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs
index 922d4bc4..92397c58 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/HarmonyRewriter.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using HarmonyLib;
using Mono.Cecil;
@@ -34,7 +36,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
public override bool Handle(ModuleDefinition module, TypeReference type, Action<TypeReference> replaceWith)
{
// detect Harmony
- if (!(type.Scope is AssemblyNameReference scope) || scope.Name != "0Harmony")
+ if (type.Scope is not AssemblyNameReference scope || scope.Name != "0Harmony")
return false;
// rewrite Harmony 1.x type to Harmony 2.0 type
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs
index 57f1dd17..fc06e779 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
@@ -37,7 +39,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
// skip if not broken
FieldDefinition fieldDefinition = fieldRef.Resolve();
- if (fieldDefinition != null && !fieldDefinition.HasConstant)
+ if (fieldDefinition?.HasConstant == false)
return false;
// rewrite if possible
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs
index 89de437e..4860072c 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs
index 9933e2ca..00daf337 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Linq;
using Mono.Cecil;
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs
index ad5cb96f..bdc4c4f3 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Mono.Cecil;
using StardewModdingAPI.Framework.ModLoading.Framework;
diff --git a/src/SMAPI/Framework/ModLoading/Symbols/SymbolReader.cs b/src/SMAPI/Framework/ModLoading/Symbols/SymbolReader.cs
index 2171895d..55b7e0c8 100644
--- a/src/SMAPI/Framework/ModLoading/Symbols/SymbolReader.cs
+++ b/src/SMAPI/Framework/ModLoading/Symbols/SymbolReader.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.IO;
using Mono.Cecil;
using Mono.Cecil.Cil;
diff --git a/src/SMAPI/Framework/ModLoading/Symbols/SymbolReaderProvider.cs b/src/SMAPI/Framework/ModLoading/Symbols/SymbolReaderProvider.cs
index 44074337..4af7c1e7 100644
--- a/src/SMAPI/Framework/ModLoading/Symbols/SymbolReaderProvider.cs
+++ b/src/SMAPI/Framework/ModLoading/Symbols/SymbolReaderProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.IO;
@@ -16,7 +18,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Symbols
private readonly ISymbolReaderProvider BaseProvider = new DefaultSymbolReaderProvider(throwIfNoSymbol: false);
/// <summary>The symbol data loaded by absolute assembly path.</summary>
- private readonly Dictionary<string, Stream> SymbolsByAssemblyPath = new Dictionary<string, Stream>(StringComparer.OrdinalIgnoreCase);
+ private readonly Dictionary<string, Stream> SymbolsByAssemblyPath = new(StringComparer.OrdinalIgnoreCase);
/*********
diff --git a/src/SMAPI/Framework/ModLoading/Symbols/SymbolWriterProvider.cs b/src/SMAPI/Framework/ModLoading/Symbols/SymbolWriterProvider.cs
index 8f7e05d1..c2ac4cd6 100644
--- a/src/SMAPI/Framework/ModLoading/Symbols/SymbolWriterProvider.cs
+++ b/src/SMAPI/Framework/ModLoading/Symbols/SymbolWriterProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.IO;
using Mono.Cecil;
using Mono.Cecil.Cil;
diff --git a/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs b/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs
index a4ac54e2..248c29fc 100644
--- a/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs
+++ b/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/SMAPI/Framework/ModRegistry.cs b/src/SMAPI/Framework/ModRegistry.cs
index ef389337..cae38637 100644
--- a/src/SMAPI/Framework/ModRegistry.cs
+++ b/src/SMAPI/Framework/ModRegistry.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -13,7 +15,7 @@ namespace StardewModdingAPI.Framework
** Fields
*********/
/// <summary>The registered mod data.</summary>
- private readonly List<IModMetadata> Mods = new List<IModMetadata>();
+ private readonly List<IModMetadata> Mods = new();
/// <summary>An assembly full name => mod lookup.</summary>
private readonly IDictionary<string, IModMetadata> ModNamesByAssembly = new Dictionary<string, IModMetadata>();
@@ -94,10 +96,8 @@ namespace StardewModdingAPI.Framework
public IModMetadata GetFromStack()
{
// get stack frames
- StackTrace stack = new StackTrace();
+ StackTrace stack = new();
StackFrame[] frames = stack.GetFrames();
- if (frames == null)
- return null;
// search stack for a source assembly
foreach (StackFrame frame in frames)
diff --git a/src/SMAPI/Framework/Models/SConfig.cs b/src/SMAPI/Framework/Models/SConfig.cs
index 9174aea6..e74d73b5 100644
--- a/src/SMAPI/Framework/Models/SConfig.cs
+++ b/src/SMAPI/Framework/Models/SConfig.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -26,7 +28,7 @@ namespace StardewModdingAPI.Framework.Models
};
/// <summary>The default values for <see cref="SuppressUpdateChecks"/>, to log changes if different.</summary>
- private static readonly HashSet<string> DefaultSuppressUpdateChecks = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
+ private static readonly HashSet<string> DefaultSuppressUpdateChecks = new(StringComparer.OrdinalIgnoreCase)
{
"SMAPI.ConsoleCommands",
"SMAPI.ErrorHandler",
@@ -52,9 +54,6 @@ namespace StardewModdingAPI.Framework.Models
/// <summary>SMAPI's GitHub project name, used to perform update checks.</summary>
public string GitHubProjectName { get; set; }
- /// <summary>Stardew64Installer's GitHub project name, used to perform update checks.</summary>
- public string Stardew64InstallerGitHubProjectName { get; set; }
-
/// <summary>The base URL for SMAPI's web API, used to perform update checks.</summary>
public string WebApiBaseUrl { get; set; }
diff --git a/src/SMAPI/Framework/Monitor.cs b/src/SMAPI/Framework/Monitor.cs
index ab76e7c0..de145d1d 100644
--- a/src/SMAPI/Framework/Monitor.cs
+++ b/src/SMAPI/Framework/Monitor.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -92,7 +94,7 @@ namespace StardewModdingAPI.Framework
public void VerboseLog(string message)
{
if (this.IsVerbose)
- this.Log(message, LogLevel.Trace);
+ this.Log(message);
}
/// <summary>Write a newline to the console and log file.</summary>
diff --git a/src/SMAPI/Framework/Networking/ModMessageModel.cs b/src/SMAPI/Framework/Networking/ModMessageModel.cs
index 4f694f9c..4e7d01eb 100644
--- a/src/SMAPI/Framework/Networking/ModMessageModel.cs
+++ b/src/SMAPI/Framework/Networking/ModMessageModel.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Linq;
using Newtonsoft.Json.Linq;
diff --git a/src/SMAPI/Framework/Networking/MultiplayerPeer.cs b/src/SMAPI/Framework/Networking/MultiplayerPeer.cs
index 3923700f..8ee5c309 100644
--- a/src/SMAPI/Framework/Networking/MultiplayerPeer.cs
+++ b/src/SMAPI/Framework/Networking/MultiplayerPeer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/SMAPI/Framework/Networking/MultiplayerPeerMod.cs b/src/SMAPI/Framework/Networking/MultiplayerPeerMod.cs
index 8087dc7e..6fdb9e54 100644
--- a/src/SMAPI/Framework/Networking/MultiplayerPeerMod.cs
+++ b/src/SMAPI/Framework/Networking/MultiplayerPeerMod.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI.Framework.Networking
{
internal class MultiplayerPeerMod : IMultiplayerPeerMod
diff --git a/src/SMAPI/Framework/Networking/RemoteContextModModel.cs b/src/SMAPI/Framework/Networking/RemoteContextModModel.cs
index 9795d971..0383576c 100644
--- a/src/SMAPI/Framework/Networking/RemoteContextModModel.cs
+++ b/src/SMAPI/Framework/Networking/RemoteContextModModel.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI.Framework.Networking
{
/// <summary>Metadata about an installed mod exchanged with connected computers.</summary>
diff --git a/src/SMAPI/Framework/Networking/RemoteContextModel.cs b/src/SMAPI/Framework/Networking/RemoteContextModel.cs
index 7befb151..37fafa67 100644
--- a/src/SMAPI/Framework/Networking/RemoteContextModel.cs
+++ b/src/SMAPI/Framework/Networking/RemoteContextModel.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI.Framework.Networking
{
/// <summary>Metadata about the game, SMAPI, and installed mods exchanged with connected computers.</summary>
diff --git a/src/SMAPI/Framework/Networking/SGalaxyNetClient.cs b/src/SMAPI/Framework/Networking/SGalaxyNetClient.cs
index 01095c66..8e19b4a7 100644
--- a/src/SMAPI/Framework/Networking/SGalaxyNetClient.cs
+++ b/src/SMAPI/Framework/Networking/SGalaxyNetClient.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Galaxy.Api;
using StardewValley.Network;
diff --git a/src/SMAPI/Framework/Networking/SGalaxyNetServer.cs b/src/SMAPI/Framework/Networking/SGalaxyNetServer.cs
index ac9cf313..07a004a2 100644
--- a/src/SMAPI/Framework/Networking/SGalaxyNetServer.cs
+++ b/src/SMAPI/Framework/Networking/SGalaxyNetServer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
@@ -45,8 +47,8 @@ namespace StardewModdingAPI.Framework.Networking
[SuppressMessage("ReSharper", "AccessToDisposedClosure", Justification = "The callback is invoked synchronously.")]
protected override void onReceiveMessage(GalaxyID peer, Stream messageStream)
{
- using IncomingMessage message = new IncomingMessage();
- using BinaryReader reader = new BinaryReader(messageStream);
+ using IncomingMessage message = new();
+ using BinaryReader reader = new(messageStream);
message.Read(reader);
ulong peerID = peer.ToUint64(); // note: GalaxyID instances get reused, so need to store the underlying ID instead
@@ -57,7 +59,7 @@ namespace StardewModdingAPI.Framework.Networking
else if (message.MessageType == StardewValley.Multiplayer.playerIntroduction)
{
NetFarmerRoot farmer = this.Multiplayer.readFarmer(message.Reader);
- GalaxyID capturedPeer = new GalaxyID(peerID);
+ GalaxyID capturedPeer = new(peerID);
this.gameServer.checkFarmhandRequest(Convert.ToString(peerID), this.getConnectionId(peer), farmer, msg => this.sendMessage(capturedPeer, msg), () => this.peers[farmer.Value.UniqueMultiplayerID] = capturedPeer.ToUint64());
}
});
diff --git a/src/SMAPI/Framework/Networking/SLidgrenClient.cs b/src/SMAPI/Framework/Networking/SLidgrenClient.cs
index 39876744..ecf18cbd 100644
--- a/src/SMAPI/Framework/Networking/SLidgrenClient.cs
+++ b/src/SMAPI/Framework/Networking/SLidgrenClient.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewValley.Network;
diff --git a/src/SMAPI/Framework/Networking/SLidgrenServer.cs b/src/SMAPI/Framework/Networking/SLidgrenServer.cs
index 05c8b872..c0b247c8 100644
--- a/src/SMAPI/Framework/Networking/SLidgrenServer.cs
+++ b/src/SMAPI/Framework/Networking/SLidgrenServer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
@@ -44,9 +46,9 @@ namespace StardewModdingAPI.Framework.Networking
{
// add hook to call multiplayer core
NetConnection peer = rawMessage.SenderConnection;
- using IncomingMessage message = new IncomingMessage();
+ using IncomingMessage message = new();
using Stream readStream = new NetBufferReadStream(rawMessage);
- using BinaryReader reader = new BinaryReader(readStream);
+ using BinaryReader reader = new(readStream);
while (rawMessage.LengthBits - rawMessage.Position >= 8)
{
diff --git a/src/SMAPI/Framework/Reflection/CacheEntry.cs b/src/SMAPI/Framework/Reflection/CacheEntry.cs
index 912662e3..6b18d204 100644
--- a/src/SMAPI/Framework/Reflection/CacheEntry.cs
+++ b/src/SMAPI/Framework/Reflection/CacheEntry.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Reflection;
namespace StardewModdingAPI.Framework.Reflection
diff --git a/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs b/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs
index 40adde8e..4c49e219 100644
--- a/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs
+++ b/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Reflection;
using System.Reflection.Emit;
using Nanoray.Pintail;
diff --git a/src/SMAPI/Framework/Reflection/ReflectedField.cs b/src/SMAPI/Framework/Reflection/ReflectedField.cs
index 3c4da4fc..921876b9 100644
--- a/src/SMAPI/Framework/Reflection/ReflectedField.cs
+++ b/src/SMAPI/Framework/Reflection/ReflectedField.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Reflection;
diff --git a/src/SMAPI/Framework/Reflection/ReflectedMethod.cs b/src/SMAPI/Framework/Reflection/ReflectedMethod.cs
index 26112806..50f89b40 100644
--- a/src/SMAPI/Framework/Reflection/ReflectedMethod.cs
+++ b/src/SMAPI/Framework/Reflection/ReflectedMethod.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Reflection;
diff --git a/src/SMAPI/Framework/Reflection/ReflectedProperty.cs b/src/SMAPI/Framework/Reflection/ReflectedProperty.cs
index 42d7bb59..a6d8c75c 100644
--- a/src/SMAPI/Framework/Reflection/ReflectedProperty.cs
+++ b/src/SMAPI/Framework/Reflection/ReflectedProperty.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Reflection;
diff --git a/src/SMAPI/Framework/Reflection/Reflector.cs b/src/SMAPI/Framework/Reflection/Reflector.cs
index 889c7ed6..d5938c3f 100644
--- a/src/SMAPI/Framework/Reflection/Reflector.cs
+++ b/src/SMAPI/Framework/Reflection/Reflector.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Linq;
using System.Reflection;
@@ -13,7 +15,7 @@ namespace StardewModdingAPI.Framework.Reflection
** Fields
*********/
/// <summary>The cached fields and methods found via reflection.</summary>
- private readonly MemoryCache Cache = new MemoryCache(typeof(Reflector).FullName);
+ private readonly MemoryCache Cache = new(typeof(Reflector).FullName);
/// <summary>The sliding cache expiration time.</summary>
private readonly TimeSpan SlidingCacheExpiry = TimeSpan.FromMinutes(5);
@@ -268,7 +270,7 @@ namespace StardewModdingAPI.Framework.Reflection
// fetch & cache new value
TMemberInfo result = fetch();
- CacheEntry cacheEntry = new CacheEntry(result != null, result);
+ CacheEntry cacheEntry = new(result != null, result);
this.Cache.Add(key, cacheEntry, new CacheItemPolicy { SlidingExpiration = this.SlidingCacheExpiry });
return result;
}
diff --git a/src/SMAPI/Framework/Rendering/SDisplayDevice.cs b/src/SMAPI/Framework/Rendering/SDisplayDevice.cs
index 85e69ae6..8718bcb1 100644
--- a/src/SMAPI/Framework/Rendering/SDisplayDevice.cs
+++ b/src/SMAPI/Framework/Rendering/SDisplayDevice.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
diff --git a/src/SMAPI/Framework/Rendering/SXnaDisplayDevice.cs b/src/SMAPI/Framework/Rendering/SXnaDisplayDevice.cs
index cb499c6b..21edaedd 100644
--- a/src/SMAPI/Framework/Rendering/SXnaDisplayDevice.cs
+++ b/src/SMAPI/Framework/Rendering/SXnaDisplayDevice.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
diff --git a/src/SMAPI/Framework/RequestExitDelegate.cs b/src/SMAPI/Framework/RequestExitDelegate.cs
index 810c399b..93ef1cf9 100644
--- a/src/SMAPI/Framework/RequestExitDelegate.cs
+++ b/src/SMAPI/Framework/RequestExitDelegate.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI.Framework
{
/// <summary>A delegate which requests that SMAPI immediately exit the game. This should only be invoked when an irrecoverable fatal error happens that risks save corruption or game-breaking bugs.</summary>
diff --git a/src/SMAPI/Framework/SChatBox.cs b/src/SMAPI/Framework/SChatBox.cs
index e000d1cd..d6286c12 100644
--- a/src/SMAPI/Framework/SChatBox.cs
+++ b/src/SMAPI/Framework/SChatBox.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using StardewValley;
using StardewValley.Menus;
diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs
index 44f46179..1a58d84b 100644
--- a/src/SMAPI/Framework/SCore.cs
+++ b/src/SMAPI/Framework/SCore.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -158,9 +160,12 @@ namespace StardewModdingAPI.Framework
/// <remarks>This is only intended for use by external code like the Error Handler mod.</remarks>
internal static SCore Instance { get; private set; }
- /// <summary>The number of update ticks which have already executed. This is similar to <see cref="Game1.ticks"/>, but incremented more consistently for every tick.</summary>
+ /// <summary>The number of game update ticks which have already executed. This is similar to <see cref="Game1.ticks"/>, but incremented more consistently for every tick.</summary>
internal static uint TicksElapsed { get; private set; }
+ /// <summary>A specialized form of <see cref="TicksElapsed"/> which is incremented each time SMAPI performs a processing tick (whether that's a game update, one wait cycle while synchronizing code, etc).</summary>
+ internal static uint ProcessTicksElapsed { get; private set; }
+
/*********
** Public methods
@@ -231,13 +236,13 @@ namespace StardewModdingAPI.Framework
this.Toolkit.JsonHelper.JsonSettings.Converters.Add(converter);
// add error handlers
- AppDomain.CurrentDomain.UnhandledException += (sender, e) => this.Monitor.Log($"Critical app domain exception: {e.ExceptionObject}", LogLevel.Error);
+ AppDomain.CurrentDomain.UnhandledException += (_, e) => this.Monitor.Log($"Critical app domain exception: {e.ExceptionObject}", LogLevel.Error);
// add more lenient assembly resolver
- AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => AssemblyLoader.ResolveAssembly(e.Name);
+ AppDomain.CurrentDomain.AssemblyResolve += (_, e) => AssemblyLoader.ResolveAssembly(e.Name);
// hook locale event
- LocalizedContentManager.OnLanguageChange += locale => this.OnLocaleChanged();
+ LocalizedContentManager.OnLanguageChange += _ => this.OnLocaleChanged();
// override game
this.Multiplayer = new SMultiplayer(this.Monitor, this.EventManager, this.Toolkit.JsonHelper, this.ModRegistry, this.Reflection, this.OnModMessageReceived, this.Settings.LogNetworkTraffic);
@@ -560,6 +565,7 @@ namespace StardewModdingAPI.Framework
finally
{
SCore.TicksElapsed++;
+ SCore.ProcessTicksElapsed++;
}
}
@@ -578,7 +584,7 @@ namespace StardewModdingAPI.Framework
*********/
if (this.JustReturnedToTitle)
{
- if (!(Game1.mapDisplayDevice is SDisplayDevice))
+ if (Game1.mapDisplayDevice is not SDisplayDevice)
Game1.mapDisplayDevice = this.GetMapDisplayDevice();
this.JustReturnedToTitle = false;
@@ -633,6 +639,8 @@ namespace StardewModdingAPI.Framework
this.Reflection.GetMethod(Game1.game1, "UpdateTitleScreen").Invoke(Game1.currentGameTime); // run game logic to change music on load, etc
while (Game1.currentLoader?.MoveNext() == true)
{
+ SCore.ProcessTicksElapsed++;
+
// raise load stage changed
switch (Game1.currentLoader.Current)
{
@@ -1446,41 +1454,6 @@ namespace StardewModdingAPI.Framework
this.LogManager.WriteUpdateMarker(updateFound.ToString(), updateUrl);
}
- // check Stardew64Installer version
- if (Constants.IsPatchedByStardew64Installer(out ISemanticVersion patchedByVersion))
- {
- ISemanticVersion updateFound = null;
- string updateUrl = null;
- try
- {
- // fetch update check
- ModEntryModel response = client.GetModInfo(new[] { new ModSearchEntryModel("Steviegt6.Stardew64Installer", patchedByVersion, new[] { $"GitHub:{this.Settings.Stardew64InstallerGitHubProjectName}" }) }, apiVersion: Constants.ApiVersion, gameVersion: Constants.GameVersion, platform: Constants.Platform).Single().Value;
- updateFound = response.SuggestedUpdate?.Version;
- updateUrl = response.SuggestedUpdate?.Url ?? Constants.HomePageUrl;
-
- // log message
- if (updateFound != null)
- this.Monitor.Log($"You can update Stardew64Installer to {updateFound}: {updateUrl}", LogLevel.Alert);
- else
- this.Monitor.Log(" Stardew64Installer okay.");
-
- // show errors
- if (response.Errors.Any())
- {
- this.Monitor.Log("Couldn't check for a new version of Stardew64Installer. 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)}");
- }
- }
- catch (Exception ex)
- {
- this.Monitor.Log("Couldn't check for a new version of Stardew64Installer. This won't affect your game, but you won't be notified of new versions if this keeps happening.", LogLevel.Warn);
- this.Monitor.Log(ex is WebException && ex.InnerException == null
- ? $"Error: {ex.Message}"
- : $"Error: {ex.GetLogSummary()}"
- );
- }
- }
-
// check mod versions
if (mods.Any())
{
@@ -1622,10 +1595,11 @@ 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)
{
// add interceptors
- if (metadata.Mod.Helper.Content is ContentHelper helper)
+ if (metadata.Mod.Helper is ModHelper helper)
{
// ReSharper disable SuspiciousTypeConversion.Global
if (metadata.Mod is IAssetEditor editor)
@@ -1653,9 +1627,11 @@ namespace StardewModdingAPI.Framework
}
// ReSharper restore SuspiciousTypeConversion.Global
- helper.ObservableAssetEditors.CollectionChanged += (sender, e) => this.OnAssetInterceptorsChanged(metadata, e.NewItems?.Cast<IAssetEditor>(), e.OldItems?.Cast<IAssetEditor>(), this.ContentCore.Editors);
- helper.ObservableAssetLoaders.CollectionChanged += (sender, e) => this.OnAssetInterceptorsChanged(metadata, e.NewItems?.Cast<IAssetLoader>(), e.OldItems?.Cast<IAssetLoader>(), this.ContentCore.Loaders);
+ ContentHelper content = helper.GetLegacyContentHelper();
+ content.ObservableAssetEditors.CollectionChanged += (_, e) => this.OnAssetInterceptorsChanged(metadata, e.NewItems?.Cast<IAssetEditor>(), e.OldItems?.Cast<IAssetEditor>(), this.ContentCore.Editors);
+ content.ObservableAssetLoaders.CollectionChanged += (_, e) => this.OnAssetInterceptorsChanged(metadata, e.NewItems?.Cast<IAssetLoader>(), e.OldItems?.Cast<IAssetLoader>(), this.ContentCore.Loaders);
}
+#pragma warning restore CS0612, CS0618
// call entry method
try
@@ -1777,10 +1753,11 @@ namespace StardewModdingAPI.Framework
{
IManifest manifest = mod.Manifest;
IMonitor monitor = this.LogManager.GetMonitor(mod.DisplayName);
+ CaseInsensitivePathCache relativePathCache = this.ContentCore.GetCaseInsensitivePathCache(mod.DirectoryPath);
GameContentHelper gameContentHelper = new(this.ContentCore, manifest.UniqueID, mod.DisplayName, monitor);
- IModContentHelper modContentHelper = new ModContentHelper(this.ContentCore, mod.DirectoryPath, manifest.UniqueID, mod.DisplayName, gameContentHelper.GetUnderlyingContentManager());
+ IModContentHelper modContentHelper = new ModContentHelper(this.ContentCore, mod.DirectoryPath, manifest.UniqueID, mod.DisplayName, gameContentHelper.GetUnderlyingContentManager(), relativePathCache);
TranslationHelper translationHelper = new(manifest.UniqueID, contentCore.GetLocale(), contentCore.Language);
- IContentPack contentPack = new ContentPack(mod.DirectoryPath, manifest, modContentHelper, translationHelper, jsonHelper);
+ IContentPack contentPack = new ContentPack(mod.DirectoryPath, manifest, modContentHelper, translationHelper, jsonHelper, relativePathCache);
mod.SetMod(contentPack, monitor, translationHelper);
this.ModRegistry.Add(mod);
@@ -1858,11 +1835,14 @@ namespace StardewModdingAPI.Framework
IContentPack CreateFakeContentPack(string packDirPath, IManifest packManifest)
{
IMonitor packMonitor = this.LogManager.GetMonitor(packManifest.Name);
+
+ CaseInsensitivePathCache relativePathCache = this.ContentCore.GetCaseInsensitivePathCache(packDirPath);
+
GameContentHelper gameContentHelper = new(contentCore, packManifest.UniqueID, packManifest.Name, packMonitor);
- IModContentHelper packContentHelper = new ModContentHelper(contentCore, packDirPath, packManifest.UniqueID, packManifest.Name, gameContentHelper.GetUnderlyingContentManager());
+ IModContentHelper packContentHelper = new ModContentHelper(contentCore, packDirPath, packManifest.UniqueID, packManifest.Name, gameContentHelper.GetUnderlyingContentManager(), relativePathCache);
TranslationHelper packTranslationHelper = new(packManifest.UniqueID, contentCore.GetLocale(), contentCore.Language);
- ContentPack contentPack = new(packDirPath, packManifest, packContentHelper, packTranslationHelper, this.Toolkit.JsonHelper);
+ ContentPack contentPack = new(packDirPath, packManifest, packContentHelper, packTranslationHelper, this.Toolkit.JsonHelper, relativePathCache);
this.ReloadTranslationsForTemporaryContentPack(mod, contentPack);
mod.FakeContentPacks.Add(new WeakReference<ContentPack>(contentPack));
return contentPack;
@@ -1870,9 +1850,12 @@ namespace StardewModdingAPI.Framework
IModEvents events = new ModEvents(mod, this.EventManager);
ICommandHelper commandHelper = new CommandHelper(mod, this.CommandManager);
- IContentHelper contentHelper = new ContentHelper(contentCore, mod.DirectoryPath, manifest.UniqueID, mod.DisplayName, monitor);
+ CaseInsensitivePathCache relativePathCache = this.ContentCore.GetCaseInsensitivePathCache(mod.DirectoryPath);
+#pragma warning disable CS0612 // deprecated code
+ ContentHelper contentHelper = new(contentCore, mod.DirectoryPath, manifest.UniqueID, mod.DisplayName, monitor);
+#pragma warning restore CS0612
GameContentHelper gameContentHelper = new(contentCore, manifest.UniqueID, mod.DisplayName, monitor);
- IModContentHelper modContentHelper = new ModContentHelper(contentCore, mod.DirectoryPath, manifest.UniqueID, mod.DisplayName, gameContentHelper.GetUnderlyingContentManager());
+ IModContentHelper modContentHelper = new ModContentHelper(contentCore, mod.DirectoryPath, manifest.UniqueID, mod.DisplayName, gameContentHelper.GetUnderlyingContentManager(), relativePathCache);
IContentPackHelper contentPackHelper = new ContentPackHelper(manifest.UniqueID, new Lazy<IContentPack[]>(GetContentPacks), CreateFakeContentPack);
IDataHelper dataHelper = new DataHelper(manifest.UniqueID, mod.DirectoryPath, jsonHelper);
IReflectionHelper reflectionHelper = new ReflectionHelper(manifest.UniqueID, mod.DisplayName, this.Reflection);
diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs
index 104cf330..7ca89eec 100644
--- a/src/SMAPI/Framework/SGame.cs
+++ b/src/SMAPI/Framework/SGame.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
@@ -37,7 +39,7 @@ namespace StardewModdingAPI.Framework
private readonly EventManager Events;
/// <summary>The maximum number of consecutive attempts SMAPI should make to recover from a draw error.</summary>
- private readonly Countdown DrawCrashTimer = new Countdown(60); // 60 ticks = roughly one second
+ private readonly Countdown DrawCrashTimer = new(60); // 60 ticks = roughly one second
/// <summary>Simplifies access to private game code.</summary>
private readonly Reflector Reflection;
@@ -71,14 +73,14 @@ namespace StardewModdingAPI.Framework
public WatcherCore Watchers { get; private set; }
/// <summary>A snapshot of the current <see cref="Watchers"/> state.</summary>
- public WatcherSnapshot WatcherSnapshot { get; } = new WatcherSnapshot();
+ public WatcherSnapshot WatcherSnapshot { get; } = new();
/// <summary>Whether the current update tick is the first one for this instance.</summary>
public bool IsFirstTick = true;
/// <summary>The number of ticks until SMAPI should notify mods that the game has loaded.</summary>
/// <remarks>Skipping a few frames ensures the game finishes initializing the world before mods try to change it.</remarks>
- public Countdown AfterLoadTimer { get; } = new Countdown(5);
+ public Countdown AfterLoadTimer { get; } = new(5);
/// <summary>Whether the game is saving and SMAPI has already raised <see cref="IGameLoopEvents.Saving"/>.</summary>
public bool IsBetweenSaveEvents { get; set; }
@@ -624,7 +626,7 @@ namespace StardewModdingAPI.Framework
if (tile != null)
{
Vector2 vector_draw_position = Game1.GlobalToLocal(Game1.viewport, tile_position * 64f);
- Location draw_location = new Location((int)vector_draw_position.X, (int)vector_draw_position.Y);
+ Location draw_location = new((int)vector_draw_position.X, (int)vector_draw_position.Y);
Game1.mapDisplayDevice.DrawTile(tile, draw_location, (tile_position.Y * 64f - 1f) / 10000f);
}
}
diff --git a/src/SMAPI/Framework/SGameRunner.cs b/src/SMAPI/Framework/SGameRunner.cs
index b816bb7c..dae314af 100644
--- a/src/SMAPI/Framework/SGameRunner.cs
+++ b/src/SMAPI/Framework/SGameRunner.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -93,7 +95,7 @@ namespace StardewModdingAPI.Framework
/// <param name="instanceIndex">The instance index.</param>
public override Game1 CreateGameInstance(PlayerIndex playerIndex = PlayerIndex.One, int instanceIndex = 0)
{
- SInputState inputState = new SInputState();
+ SInputState inputState = new();
return new SGame(playerIndex, instanceIndex, this.Monitor, this.Reflection, this.Events, inputState, this.ModHooks, this.Multiplayer, this.ExitGameImmediately, this.OnPlayerInstanceUpdating, this.OnGameContentLoaded);
}
diff --git a/src/SMAPI/Framework/SModHooks.cs b/src/SMAPI/Framework/SModHooks.cs
index 101e022a..7941e102 100644
--- a/src/SMAPI/Framework/SModHooks.cs
+++ b/src/SMAPI/Framework/SModHooks.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Threading.Tasks;
using StardewValley;
diff --git a/src/SMAPI/Framework/SMultiplayer.cs b/src/SMAPI/Framework/SMultiplayer.cs
index 5956b63f..de3c25a5 100644
--- a/src/SMAPI/Framework/SMultiplayer.cs
+++ b/src/SMAPI/Framework/SMultiplayer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.IO;
@@ -56,10 +58,10 @@ namespace StardewModdingAPI.Framework
private readonly bool LogNetworkTraffic;
/// <summary>The backing field for <see cref="Peers"/>.</summary>
- private readonly PerScreen<IDictionary<long, MultiplayerPeer>> PeersImpl = new PerScreen<IDictionary<long, MultiplayerPeer>>(() => new Dictionary<long, MultiplayerPeer>());
+ private readonly PerScreen<IDictionary<long, MultiplayerPeer>> PeersImpl = new(() => new Dictionary<long, MultiplayerPeer>());
/// <summary>The backing field for <see cref="HostPeer"/>.</summary>
- private readonly PerScreen<MultiplayerPeer> HostPeerImpl = new PerScreen<MultiplayerPeer>();
+ private readonly PerScreen<MultiplayerPeer> HostPeerImpl = new();
/*********
@@ -111,20 +113,20 @@ namespace StardewModdingAPI.Framework
{
switch (client)
{
- case LidgrenClient _:
+ case LidgrenClient:
{
string address = this.Reflection.GetField<string>(client, "address").GetValue();
return new SLidgrenClient(address, this.OnClientProcessingMessage, this.OnClientSendingMessage);
}
- case GalaxyNetClient _:
+ case GalaxyNetClient:
{
GalaxyID address = this.Reflection.GetField<GalaxyID>(client, "lobbyId").GetValue();
return new SGalaxyNetClient(address, this.OnClientProcessingMessage, this.OnClientSendingMessage);
}
default:
- this.Monitor.Log($"Unknown multiplayer client type: {client.GetType().AssemblyQualifiedName}", LogLevel.Trace);
+ this.Monitor.Log($"Unknown multiplayer client type: {client.GetType().AssemblyQualifiedName}");
return client;
}
}
@@ -135,20 +137,20 @@ namespace StardewModdingAPI.Framework
{
switch (server)
{
- case LidgrenServer _:
+ case LidgrenServer:
{
IGameServer gameServer = this.Reflection.GetField<IGameServer>(server, "gameServer").GetValue();
return new SLidgrenServer(gameServer, this, this.OnServerProcessingMessage);
}
- case GalaxyNetServer _:
+ case GalaxyNetServer:
{
IGameServer gameServer = this.Reflection.GetField<IGameServer>(server, "gameServer").GetValue();
return new SGalaxyNetServer(gameServer, this, this.OnServerProcessingMessage);
}
default:
- this.Monitor.Log($"Unknown multiplayer server type: {server.GetType().AssemblyQualifiedName}", LogLevel.Trace);
+ this.Monitor.Log($"Unknown multiplayer server type: {server.GetType().AssemblyQualifiedName}");
return server;
}
}
@@ -160,7 +162,7 @@ namespace StardewModdingAPI.Framework
protected void OnClientSendingMessage(OutgoingMessage message, Action<OutgoingMessage> sendMessage, Action resume)
{
if (this.LogNetworkTraffic)
- this.Monitor.Log($"CLIENT SEND {(MessageType)message.MessageType} {message.FarmerID}", LogLevel.Trace);
+ this.Monitor.Log($"CLIENT SEND {(MessageType)message.MessageType} {message.FarmerID}");
switch (message.MessageType)
{
@@ -184,7 +186,7 @@ namespace StardewModdingAPI.Framework
public void OnServerProcessingMessage(IncomingMessage message, Action<OutgoingMessage> sendMessage, Action resume)
{
if (this.LogNetworkTraffic)
- this.Monitor.Log($"SERVER RECV {(MessageType)message.MessageType} {message.FarmerID}", LogLevel.Trace);
+ this.Monitor.Log($"SERVER RECV {(MessageType)message.MessageType} {message.FarmerID}");
switch (message.MessageType)
{
@@ -193,10 +195,10 @@ namespace StardewModdingAPI.Framework
{
// parse message
RemoteContextModel model = this.ReadContext(message.Reader);
- this.Monitor.Log($"Received context for farmhand {message.FarmerID} running {(model != null ? $"SMAPI {model.ApiVersion} with {model.Mods.Length} mods" : "vanilla")}.", LogLevel.Trace);
+ this.Monitor.Log($"Received context for farmhand {message.FarmerID} running {(model != null ? $"SMAPI {model.ApiVersion} with {model.Mods.Length} mods" : "vanilla")}.");
// store peer
- MultiplayerPeer newPeer = new MultiplayerPeer(
+ MultiplayerPeer newPeer = new(
playerID: message.FarmerID,
screenID: this.GetScreenId(message.FarmerID),
model: model,
@@ -243,8 +245,8 @@ namespace StardewModdingAPI.Framework
// store peer if new
if (!this.Peers.ContainsKey(message.FarmerID))
{
- this.Monitor.Log($"Received connection for vanilla player {message.FarmerID}.", LogLevel.Trace);
- MultiplayerPeer peer = new MultiplayerPeer(
+ this.Monitor.Log($"Received connection for vanilla player {message.FarmerID}.");
+ MultiplayerPeer peer = new(
playerID: message.FarmerID,
screenID: this.GetScreenId(message.FarmerID),
model: null,
@@ -280,7 +282,7 @@ namespace StardewModdingAPI.Framework
public void OnClientProcessingMessage(IncomingMessage message, Action<OutgoingMessage> sendMessage, Action resume)
{
if (this.LogNetworkTraffic)
- this.Monitor.Log($"CLIENT RECV {(MessageType)message.MessageType} {message.FarmerID}", LogLevel.Trace);
+ this.Monitor.Log($"CLIENT RECV {(MessageType)message.MessageType} {message.FarmerID}");
switch (message.MessageType)
{
@@ -289,10 +291,10 @@ namespace StardewModdingAPI.Framework
{
// parse message
RemoteContextModel model = this.ReadContext(message.Reader);
- this.Monitor.Log($"Received context for {(model?.IsHost == true ? "host" : "farmhand")} {message.FarmerID} running {(model != null ? $"SMAPI {model.ApiVersion} with {model.Mods.Length} mods" : "vanilla")}.", LogLevel.Trace);
+ this.Monitor.Log($"Received context for {(model?.IsHost == true ? "host" : "farmhand")} {message.FarmerID} running {(model != null ? $"SMAPI {model.ApiVersion} with {model.Mods.Length} mods" : "vanilla")}.");
// store peer
- MultiplayerPeer peer = new MultiplayerPeer(
+ MultiplayerPeer peer = new(
playerID: message.FarmerID,
screenID: this.GetScreenId(message.FarmerID),
model: model,
@@ -314,7 +316,7 @@ namespace StardewModdingAPI.Framework
// store peer
if (!this.Peers.ContainsKey(message.FarmerID) && this.HostPeer == null)
{
- this.Monitor.Log($"Received connection for vanilla host {message.FarmerID}.", LogLevel.Trace);
+ this.Monitor.Log($"Received connection for vanilla host {message.FarmerID}.");
var peer = new MultiplayerPeer(
playerID: message.FarmerID,
screenID: this.GetScreenId(message.FarmerID),
@@ -341,7 +343,7 @@ namespace StardewModdingAPI.Framework
sendMessage: sendMessage,
isHost: this.HostPeer == null
);
- this.Monitor.Log($"Received connection for vanilla {(peer.IsHost ? "host" : "farmhand")} {message.FarmerID}.", LogLevel.Trace);
+ this.Monitor.Log($"Received connection for vanilla {(peer.IsHost ? "host" : "farmhand")} {message.FarmerID}.");
this.AddPeer(peer, canBeHost: true);
}
@@ -367,7 +369,7 @@ namespace StardewModdingAPI.Framework
{
if (this.Peers.TryGetValue(playerID, out MultiplayerPeer peer))
{
- this.Monitor.Log($"Player quit: {playerID}", LogLevel.Trace);
+ this.Monitor.Log($"Player quit: {playerID}");
this.Peers.Remove(playerID);
this.EventManager.PeerDisconnected.Raise(new PeerDisconnectedEventArgs(peer));
}
@@ -420,7 +422,7 @@ namespace StardewModdingAPI.Framework
}
// get data to send
- ModMessageModel model = new ModMessageModel(
+ ModMessageModel model = new(
fromPlayerID: Game1.player.UniqueMultiplayerID,
fromModID: fromModID,
toModIDs: toModIDs,
@@ -434,7 +436,7 @@ namespace StardewModdingAPI.Framework
if (sendToSelf)
{
if (this.LogNetworkTraffic)
- this.Monitor.Log($"Broadcasting '{messageType}' message to self: {data}.", LogLevel.Trace);
+ this.Monitor.Log($"Broadcasting '{messageType}' message to self: {data}.");
this.OnModMessageReceived(model);
}
@@ -447,7 +449,7 @@ namespace StardewModdingAPI.Framework
foreach (MultiplayerPeer peer in sendToPeers)
{
if (this.LogNetworkTraffic)
- this.Monitor.Log($"Broadcasting '{messageType}' message to farmhand {peer.PlayerID}: {data}.", LogLevel.Trace);
+ this.Monitor.Log($"Broadcasting '{messageType}' message to farmhand {peer.PlayerID}: {data}.");
peer.SendMessage(new OutgoingMessage((byte)MessageType.ModMessage, peer.PlayerID, data));
}
@@ -455,7 +457,7 @@ namespace StardewModdingAPI.Framework
else if (this.HostPeer?.HasSmapi == true)
{
if (this.LogNetworkTraffic)
- this.Monitor.Log($"Broadcasting '{messageType}' message to host {this.HostPeer.PlayerID}: {data}.", LogLevel.Trace);
+ this.Monitor.Log($"Broadcasting '{messageType}' message to host {this.HostPeer.PlayerID}: {data}.");
this.HostPeer.SendMessage(new OutgoingMessage((byte)MessageType.ModMessage, this.HostPeer.PlayerID, data));
}
@@ -504,7 +506,7 @@ namespace StardewModdingAPI.Framework
ModMessageModel model = this.JsonHelper.Deserialize<ModMessageModel>(json);
HashSet<long> playerIDs = new HashSet<long>(model.ToPlayerIDs ?? this.GetKnownPlayerIDs());
if (this.LogNetworkTraffic)
- this.Monitor.Log($"Received message: {json}.", LogLevel.Trace);
+ this.Monitor.Log($"Received message: {json}.");
// notify local mods
if (playerIDs.Contains(Game1.player.UniqueMultiplayerID))
@@ -513,7 +515,7 @@ namespace StardewModdingAPI.Framework
// forward to other players
if (Context.IsMainPlayer && playerIDs.Any(p => p != Game1.player.UniqueMultiplayerID))
{
- ModMessageModel newModel = new ModMessageModel(model);
+ ModMessageModel newModel = new(model);
foreach (long playerID in playerIDs)
{
if (playerID != Game1.player.UniqueMultiplayerID && playerID != model.FromPlayerID && this.Peers.TryGetValue(playerID, out MultiplayerPeer peer))
@@ -544,7 +546,7 @@ namespace StardewModdingAPI.Framework
/// <summary>Get the fields to include in a context sync message sent to other players.</summary>
private object[] GetContextSyncMessageFields()
{
- RemoteContextModel model = new RemoteContextModel
+ RemoteContextModel model = new()
{
IsHost = Context.IsWorldReady && Context.IsMainPlayer,
Platform = Constants.TargetPlatform,
@@ -571,7 +573,7 @@ namespace StardewModdingAPI.Framework
if (!peer.HasSmapi)
return new object[] { "{}" };
- RemoteContextModel model = new RemoteContextModel
+ RemoteContextModel model = new()
{
IsHost = peer.IsHost,
Platform = peer.Platform.Value,
diff --git a/src/SMAPI/Framework/Serialization/KeybindConverter.cs b/src/SMAPI/Framework/Serialization/KeybindConverter.cs
index 93a274a8..f3bab20d 100644
--- a/src/SMAPI/Framework/Serialization/KeybindConverter.cs
+++ b/src/SMAPI/Framework/Serialization/KeybindConverter.cs
@@ -36,7 +36,7 @@ namespace StardewModdingAPI.Framework.Serialization
/// <param name="objectType">The object type.</param>
/// <param name="existingValue">The object being read.</param>
/// <param name="serializer">The calling serializer.</param>
- public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
string path = reader.Path;
@@ -44,7 +44,7 @@ namespace StardewModdingAPI.Framework.Serialization
{
case JsonToken.Null:
return objectType == typeof(Keybind)
- ? (object)new Keybind()
+ ? new Keybind()
: new KeybindList();
case JsonToken.String:
@@ -74,7 +74,7 @@ namespace StardewModdingAPI.Framework.Serialization
/// <param name="writer">The JSON writer.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
writer.WriteValue(value?.ToString());
}
diff --git a/src/SMAPI/Framework/Singleton.cs b/src/SMAPI/Framework/Singleton.cs
index 399a8bf0..da16c48e 100644
--- a/src/SMAPI/Framework/Singleton.cs
+++ b/src/SMAPI/Framework/Singleton.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI.Framework
{
/// <summary>Provides singleton instances of a given type.</summary>
@@ -5,6 +7,6 @@ namespace StardewModdingAPI.Framework
internal static class Singleton<T> where T : new()
{
/// <summary>The singleton instance.</summary>
- public static T Instance { get; } = new T();
+ public static T Instance { get; } = new();
}
}
diff --git a/src/SMAPI/Framework/SnapshotDiff.cs b/src/SMAPI/Framework/SnapshotDiff.cs
index 5b6288ff..eb2aebe1 100644
--- a/src/SMAPI/Framework/SnapshotDiff.cs
+++ b/src/SMAPI/Framework/SnapshotDiff.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using StardewModdingAPI.Framework.StateTracking;
namespace StardewModdingAPI.Framework
diff --git a/src/SMAPI/Framework/SnapshotItemListDiff.cs b/src/SMAPI/Framework/SnapshotItemListDiff.cs
index e8ab1b1e..97942783 100644
--- a/src/SMAPI/Framework/SnapshotItemListDiff.cs
+++ b/src/SMAPI/Framework/SnapshotItemListDiff.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Linq;
using StardewModdingAPI.Events;
diff --git a/src/SMAPI/Framework/SnapshotListDiff.cs b/src/SMAPI/Framework/SnapshotListDiff.cs
index 2d0efa0d..1d585c15 100644
--- a/src/SMAPI/Framework/SnapshotListDiff.cs
+++ b/src/SMAPI/Framework/SnapshotListDiff.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using StardewModdingAPI.Framework.StateTracking;
@@ -11,10 +13,10 @@ namespace StardewModdingAPI.Framework
** Fields
*********/
/// <summary>The removed values.</summary>
- private readonly List<T> RemovedImpl = new List<T>();
+ private readonly List<T> RemovedImpl = new();
/// <summary>The added values.</summary>
- private readonly List<T> AddedImpl = new List<T>();
+ private readonly List<T> AddedImpl = new();
/*********
diff --git a/src/SMAPI/Framework/StateTracking/ChestTracker.cs b/src/SMAPI/Framework/StateTracking/ChestTracker.cs
index 65f58ee7..28335200 100644
--- a/src/SMAPI/Framework/StateTracking/ChestTracker.cs
+++ b/src/SMAPI/Framework/StateTracking/ChestTracker.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -18,10 +20,10 @@ namespace StardewModdingAPI.Framework.StateTracking
private readonly IDictionary<Item, int> StackSizes;
/// <summary>Items added since the last update.</summary>
- private readonly HashSet<Item> Added = new HashSet<Item>(new ObjectReferenceComparer<Item>());
+ private readonly HashSet<Item> Added = new(new ObjectReferenceComparer<Item>());
/// <summary>Items removed since the last update.</summary>
- private readonly HashSet<Item> Removed = new HashSet<Item>(new ObjectReferenceComparer<Item>());
+ private readonly HashSet<Item> Removed = new(new ObjectReferenceComparer<Item>());
/// <summary>The underlying inventory watcher.</summary>
private readonly ICollectionWatcher<Item> InventoryWatcher;
diff --git a/src/SMAPI/Framework/StateTracking/Comparers/EquatableComparer.cs b/src/SMAPI/Framework/StateTracking/Comparers/EquatableComparer.cs
index a96ffdb6..987e1820 100644
--- a/src/SMAPI/Framework/StateTracking/Comparers/EquatableComparer.cs
+++ b/src/SMAPI/Framework/StateTracking/Comparers/EquatableComparer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
diff --git a/src/SMAPI/Framework/StateTracking/Comparers/GenericEqualsComparer.cs b/src/SMAPI/Framework/StateTracking/Comparers/GenericEqualsComparer.cs
index cc1d6553..f6b04583 100644
--- a/src/SMAPI/Framework/StateTracking/Comparers/GenericEqualsComparer.cs
+++ b/src/SMAPI/Framework/StateTracking/Comparers/GenericEqualsComparer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Runtime.CompilerServices;
diff --git a/src/SMAPI/Framework/StateTracking/Comparers/ObjectReferenceComparer.cs b/src/SMAPI/Framework/StateTracking/Comparers/ObjectReferenceComparer.cs
index ef9adafb..8d3a7eb9 100644
--- a/src/SMAPI/Framework/StateTracking/Comparers/ObjectReferenceComparer.cs
+++ b/src/SMAPI/Framework/StateTracking/Comparers/ObjectReferenceComparer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Runtime.CompilerServices;
diff --git a/src/SMAPI/Framework/StateTracking/FieldWatchers/BaseDisposableWatcher.cs b/src/SMAPI/Framework/StateTracking/FieldWatchers/BaseDisposableWatcher.cs
index 60006c51..03bf84d9 100644
--- a/src/SMAPI/Framework/StateTracking/FieldWatchers/BaseDisposableWatcher.cs
+++ b/src/SMAPI/Framework/StateTracking/FieldWatchers/BaseDisposableWatcher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Framework.StateTracking.FieldWatchers
diff --git a/src/SMAPI/Framework/StateTracking/FieldWatchers/ComparableListWatcher.cs b/src/SMAPI/Framework/StateTracking/FieldWatchers/ComparableListWatcher.cs
index 32ec8c7e..52e1dbad 100644
--- a/src/SMAPI/Framework/StateTracking/FieldWatchers/ComparableListWatcher.cs
+++ b/src/SMAPI/Framework/StateTracking/FieldWatchers/ComparableListWatcher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Linq;
@@ -17,10 +19,10 @@ namespace StardewModdingAPI.Framework.StateTracking.FieldWatchers
private HashSet<TValue> LastValues;
/// <summary>The pairs added since the last reset.</summary>
- private readonly List<TValue> AddedImpl = new List<TValue>();
+ private readonly List<TValue> AddedImpl = new();
/// <summary>The pairs removed since the last reset.</summary>
- private readonly List<TValue> RemovedImpl = new List<TValue>();
+ private readonly List<TValue> RemovedImpl = new();
/*********
diff --git a/src/SMAPI/Framework/StateTracking/FieldWatchers/ComparableWatcher.cs b/src/SMAPI/Framework/StateTracking/FieldWatchers/ComparableWatcher.cs
index 5ca4b9f4..4f94294c 100644
--- a/src/SMAPI/Framework/StateTracking/FieldWatchers/ComparableWatcher.cs
+++ b/src/SMAPI/Framework/StateTracking/FieldWatchers/ComparableWatcher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
diff --git a/src/SMAPI/Framework/StateTracking/FieldWatchers/ImmutableCollectionWatcher.cs b/src/SMAPI/Framework/StateTracking/FieldWatchers/ImmutableCollectionWatcher.cs
index 009e0282..94ce0c8e 100644
--- a/src/SMAPI/Framework/StateTracking/FieldWatchers/ImmutableCollectionWatcher.cs
+++ b/src/SMAPI/Framework/StateTracking/FieldWatchers/ImmutableCollectionWatcher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
@@ -11,7 +13,7 @@ namespace StardewModdingAPI.Framework.StateTracking.FieldWatchers
** Accessors
*********/
/// <summary>A singleton collection watcher instance.</summary>
- public static ImmutableCollectionWatcher<TValue> Instance { get; } = new ImmutableCollectionWatcher<TValue>();
+ public static ImmutableCollectionWatcher<TValue> Instance { get; } = new();
/// <summary>Whether the collection changed since the last reset.</summary>
public bool IsChanged { get; } = false;
diff --git a/src/SMAPI/Framework/StateTracking/FieldWatchers/NetCollectionWatcher.cs b/src/SMAPI/Framework/StateTracking/FieldWatchers/NetCollectionWatcher.cs
index 21e84c47..e662c433 100644
--- a/src/SMAPI/Framework/StateTracking/FieldWatchers/NetCollectionWatcher.cs
+++ b/src/SMAPI/Framework/StateTracking/FieldWatchers/NetCollectionWatcher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using Netcode;
@@ -15,10 +17,10 @@ namespace StardewModdingAPI.Framework.StateTracking.FieldWatchers
private readonly NetCollection<TValue> Field;
/// <summary>The pairs added since the last reset.</summary>
- private readonly List<TValue> AddedImpl = new List<TValue>();
+ private readonly List<TValue> AddedImpl = new();
/// <summary>The pairs removed since the last reset.</summary>
- private readonly List<TValue> RemovedImpl = new List<TValue>();
+ private readonly List<TValue> RemovedImpl = new();
/*********
diff --git a/src/SMAPI/Framework/StateTracking/FieldWatchers/NetDictionaryWatcher.cs b/src/SMAPI/Framework/StateTracking/FieldWatchers/NetDictionaryWatcher.cs
index e6882f7e..0d7f2ad2 100644
--- a/src/SMAPI/Framework/StateTracking/FieldWatchers/NetDictionaryWatcher.cs
+++ b/src/SMAPI/Framework/StateTracking/FieldWatchers/NetDictionaryWatcher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using Netcode;
diff --git a/src/SMAPI/Framework/StateTracking/FieldWatchers/NetListWatcher.cs b/src/SMAPI/Framework/StateTracking/FieldWatchers/NetListWatcher.cs
index 0b4d3030..a97e754c 100644
--- a/src/SMAPI/Framework/StateTracking/FieldWatchers/NetListWatcher.cs
+++ b/src/SMAPI/Framework/StateTracking/FieldWatchers/NetListWatcher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using Netcode;
using StardewModdingAPI.Framework.StateTracking.Comparers;
diff --git a/src/SMAPI/Framework/StateTracking/FieldWatchers/NetValueWatcher.cs b/src/SMAPI/Framework/StateTracking/FieldWatchers/NetValueWatcher.cs
index 48d5d681..26641750 100644
--- a/src/SMAPI/Framework/StateTracking/FieldWatchers/NetValueWatcher.cs
+++ b/src/SMAPI/Framework/StateTracking/FieldWatchers/NetValueWatcher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using Netcode;
namespace StardewModdingAPI.Framework.StateTracking.FieldWatchers
diff --git a/src/SMAPI/Framework/StateTracking/FieldWatchers/ObservableCollectionWatcher.cs b/src/SMAPI/Framework/StateTracking/FieldWatchers/ObservableCollectionWatcher.cs
index c29d2783..82e5387e 100644
--- a/src/SMAPI/Framework/StateTracking/FieldWatchers/ObservableCollectionWatcher.cs
+++ b/src/SMAPI/Framework/StateTracking/FieldWatchers/ObservableCollectionWatcher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
@@ -16,13 +18,13 @@ namespace StardewModdingAPI.Framework.StateTracking.FieldWatchers
private readonly ObservableCollection<TValue> Field;
/// <summary>The pairs added since the last reset.</summary>
- private readonly List<TValue> AddedImpl = new List<TValue>();
+ private readonly List<TValue> AddedImpl = new();
/// <summary>The pairs removed since the last reset.</summary>
- private readonly List<TValue> RemovedImpl = new List<TValue>();
+ private readonly List<TValue> RemovedImpl = new();
/// <summary>The previous values as of the last update.</summary>
- private readonly List<TValue> PreviousValues = new List<TValue>();
+ private readonly List<TValue> PreviousValues = new();
/*********
diff --git a/src/SMAPI/Framework/StateTracking/FieldWatchers/WatcherFactory.cs b/src/SMAPI/Framework/StateTracking/FieldWatchers/WatcherFactory.cs
index bde43486..0b99914c 100644
--- a/src/SMAPI/Framework/StateTracking/FieldWatchers/WatcherFactory.cs
+++ b/src/SMAPI/Framework/StateTracking/FieldWatchers/WatcherFactory.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
diff --git a/src/SMAPI/Framework/StateTracking/ICollectionWatcher.cs b/src/SMAPI/Framework/StateTracking/ICollectionWatcher.cs
index 7a7759e3..74c9313b 100644
--- a/src/SMAPI/Framework/StateTracking/ICollectionWatcher.cs
+++ b/src/SMAPI/Framework/StateTracking/ICollectionWatcher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
namespace StardewModdingAPI.Framework.StateTracking
diff --git a/src/SMAPI/Framework/StateTracking/IDictionaryWatcher.cs b/src/SMAPI/Framework/StateTracking/IDictionaryWatcher.cs
index 691ed377..81fb7460 100644
--- a/src/SMAPI/Framework/StateTracking/IDictionaryWatcher.cs
+++ b/src/SMAPI/Framework/StateTracking/IDictionaryWatcher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
namespace StardewModdingAPI.Framework.StateTracking
diff --git a/src/SMAPI/Framework/StateTracking/IValueWatcher.cs b/src/SMAPI/Framework/StateTracking/IValueWatcher.cs
index 4afca972..7d46053c 100644
--- a/src/SMAPI/Framework/StateTracking/IValueWatcher.cs
+++ b/src/SMAPI/Framework/StateTracking/IValueWatcher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI.Framework.StateTracking
{
/// <summary>A watcher which tracks changes to a value.</summary>
diff --git a/src/SMAPI/Framework/StateTracking/IWatcher.cs b/src/SMAPI/Framework/StateTracking/IWatcher.cs
index 8c7fa51c..3603b6f8 100644
--- a/src/SMAPI/Framework/StateTracking/IWatcher.cs
+++ b/src/SMAPI/Framework/StateTracking/IWatcher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI.Framework.StateTracking
diff --git a/src/SMAPI/Framework/StateTracking/LocationTracker.cs b/src/SMAPI/Framework/StateTracking/LocationTracker.cs
index 748e4ecc..9c2ff7f0 100644
--- a/src/SMAPI/Framework/StateTracking/LocationTracker.cs
+++ b/src/SMAPI/Framework/StateTracking/LocationTracker.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -19,7 +21,7 @@ namespace StardewModdingAPI.Framework.StateTracking
** Fields
*********/
/// <summary>The underlying watchers.</summary>
- private readonly List<IWatcher> Watchers = new List<IWatcher>();
+ private readonly List<IWatcher> Watchers = new();
/*********
diff --git a/src/SMAPI/Framework/StateTracking/PlayerTracker.cs b/src/SMAPI/Framework/StateTracking/PlayerTracker.cs
index cf49a7c1..367eafea 100644
--- a/src/SMAPI/Framework/StateTracking/PlayerTracker.cs
+++ b/src/SMAPI/Framework/StateTracking/PlayerTracker.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -24,7 +26,7 @@ namespace StardewModdingAPI.Framework.StateTracking
private GameLocation LastValidLocation;
/// <summary>The underlying watchers.</summary>
- private readonly List<IWatcher> Watchers = new List<IWatcher>();
+ private readonly List<IWatcher> Watchers = new();
/*********
diff --git a/src/SMAPI/Framework/StateTracking/Snapshots/LocationSnapshot.cs b/src/SMAPI/Framework/StateTracking/Snapshots/LocationSnapshot.cs
index 6c9cc4f5..3d13f92b 100644
--- a/src/SMAPI/Framework/StateTracking/Snapshots/LocationSnapshot.cs
+++ b/src/SMAPI/Framework/StateTracking/Snapshots/LocationSnapshot.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using StardewValley;
@@ -17,25 +19,25 @@ namespace StardewModdingAPI.Framework.StateTracking.Snapshots
public GameLocation Location { get; }
/// <summary>Tracks added or removed buildings.</summary>
- public SnapshotListDiff<Building> Buildings { get; } = new SnapshotListDiff<Building>();
+ public SnapshotListDiff<Building> Buildings { get; } = new();
/// <summary>Tracks added or removed debris.</summary>
- public SnapshotListDiff<Debris> Debris { get; } = new SnapshotListDiff<Debris>();
+ public SnapshotListDiff<Debris> Debris { get; } = new();
/// <summary>Tracks added or removed large terrain features.</summary>
- public SnapshotListDiff<LargeTerrainFeature> LargeTerrainFeatures { get; } = new SnapshotListDiff<LargeTerrainFeature>();
+ public SnapshotListDiff<LargeTerrainFeature> LargeTerrainFeatures { get; } = new();
/// <summary>Tracks added or removed NPCs.</summary>
- public SnapshotListDiff<NPC> Npcs { get; } = new SnapshotListDiff<NPC>();
+ public SnapshotListDiff<NPC> Npcs { get; } = new();
/// <summary>Tracks added or removed objects.</summary>
- public SnapshotListDiff<KeyValuePair<Vector2, Object>> Objects { get; } = new SnapshotListDiff<KeyValuePair<Vector2, Object>>();
+ public SnapshotListDiff<KeyValuePair<Vector2, Object>> Objects { get; } = new();
/// <summary>Tracks added or removed terrain features.</summary>
- public SnapshotListDiff<KeyValuePair<Vector2, TerrainFeature>> TerrainFeatures { get; } = new SnapshotListDiff<KeyValuePair<Vector2, TerrainFeature>>();
+ public SnapshotListDiff<KeyValuePair<Vector2, TerrainFeature>> TerrainFeatures { get; } = new();
/// <summary>Tracks added or removed furniture.</summary>
- public SnapshotListDiff<Furniture> Furniture { get; } = new SnapshotListDiff<Furniture>();
+ public SnapshotListDiff<Furniture> Furniture { get; } = new();
/// <summary>Tracks changed chest inventories.</summary>
public IDictionary<Chest, SnapshotItemListDiff> ChestItems { get; } = new Dictionary<Chest, SnapshotItemListDiff>();
diff --git a/src/SMAPI/Framework/StateTracking/Snapshots/PlayerSnapshot.cs b/src/SMAPI/Framework/StateTracking/Snapshots/PlayerSnapshot.cs
index 72f45a87..bf81a35e 100644
--- a/src/SMAPI/Framework/StateTracking/Snapshots/PlayerSnapshot.cs
+++ b/src/SMAPI/Framework/StateTracking/Snapshots/PlayerSnapshot.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -14,7 +16,7 @@ namespace StardewModdingAPI.Framework.StateTracking.Snapshots
** Fields
*********/
/// <summary>An empty item list diff.</summary>
- private readonly SnapshotItemListDiff EmptyItemListDiff = new SnapshotItemListDiff(Array.Empty<Item>(), Array.Empty<Item>(), Array.Empty<ItemStackSizeChange>());
+ private readonly SnapshotItemListDiff EmptyItemListDiff = new(Array.Empty<Item>(), Array.Empty<Item>(), Array.Empty<ItemStackSizeChange>());
/*********
@@ -24,14 +26,14 @@ namespace StardewModdingAPI.Framework.StateTracking.Snapshots
public Farmer Player { get; }
/// <summary>The player's current location.</summary>
- public SnapshotDiff<GameLocation> Location { get; } = new SnapshotDiff<GameLocation>();
+ public SnapshotDiff<GameLocation> Location { get; } = new();
/// <summary>Tracks changes to the player's skill levels.</summary>
public IDictionary<SkillType, SnapshotDiff<int>> Skills { get; } =
Enum
.GetValues(typeof(SkillType))
.Cast<SkillType>()
- .ToDictionary(skill => skill, skill => new SnapshotDiff<int>());
+ .ToDictionary(skill => skill, _ => new SnapshotDiff<int>());
/// <summary>Get a list of inventory changes.</summary>
public SnapshotItemListDiff Inventory { get; private set; }
diff --git a/src/SMAPI/Framework/StateTracking/Snapshots/WatcherSnapshot.cs b/src/SMAPI/Framework/StateTracking/Snapshots/WatcherSnapshot.cs
index cf51e040..1d43ef26 100644
--- a/src/SMAPI/Framework/StateTracking/Snapshots/WatcherSnapshot.cs
+++ b/src/SMAPI/Framework/StateTracking/Snapshots/WatcherSnapshot.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using Microsoft.Xna.Framework;
using StardewValley;
using StardewValley.Menus;
@@ -11,31 +13,31 @@ namespace StardewModdingAPI.Framework.StateTracking.Snapshots
** Accessors
*********/
/// <summary>Tracks changes to the window size.</summary>
- public SnapshotDiff<Point> WindowSize { get; } = new SnapshotDiff<Point>();
+ public SnapshotDiff<Point> WindowSize { get; } = new();
/// <summary>Tracks changes to the current player.</summary>
public PlayerSnapshot CurrentPlayer { get; private set; }
/// <summary>Tracks changes to the time of day (in 24-hour military format).</summary>
- public SnapshotDiff<int> Time { get; } = new SnapshotDiff<int>();
+ public SnapshotDiff<int> Time { get; } = new();
/// <summary>Tracks changes to the save ID.</summary>
- public SnapshotDiff<ulong> SaveID { get; } = new SnapshotDiff<ulong>();
+ public SnapshotDiff<ulong> SaveID { get; } = new();
/// <summary>Tracks changes to the game's locations.</summary>
- public WorldLocationsSnapshot Locations { get; } = new WorldLocationsSnapshot();
+ public WorldLocationsSnapshot Locations { get; } = new();
/// <summary>Tracks changes to <see cref="Game1.activeClickableMenu"/>.</summary>
- public SnapshotDiff<IClickableMenu> ActiveMenu { get; } = new SnapshotDiff<IClickableMenu>();
+ public SnapshotDiff<IClickableMenu> ActiveMenu { get; } = new();
/// <summary>Tracks changes to the cursor position.</summary>
- public SnapshotDiff<ICursorPosition> Cursor { get; } = new SnapshotDiff<ICursorPosition>();
+ public SnapshotDiff<ICursorPosition> Cursor { get; } = new();
/// <summary>Tracks changes to the mouse wheel scroll.</summary>
- public SnapshotDiff<int> MouseWheelScroll { get; } = new SnapshotDiff<int>();
+ public SnapshotDiff<int> MouseWheelScroll { get; } = new();
/// <summary>Tracks changes to the content locale.</summary>
- public SnapshotDiff<LocalizedContentManager.LanguageCode> Locale { get; } = new SnapshotDiff<LocalizedContentManager.LanguageCode>();
+ public SnapshotDiff<LocalizedContentManager.LanguageCode> Locale { get; } = new();
/*********
diff --git a/src/SMAPI/Framework/StateTracking/Snapshots/WorldLocationsSnapshot.cs b/src/SMAPI/Framework/StateTracking/Snapshots/WorldLocationsSnapshot.cs
index 73ed2d8f..88aac0df 100644
--- a/src/SMAPI/Framework/StateTracking/Snapshots/WorldLocationsSnapshot.cs
+++ b/src/SMAPI/Framework/StateTracking/Snapshots/WorldLocationsSnapshot.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Linq;
using StardewModdingAPI.Framework.StateTracking.Comparers;
@@ -12,14 +14,14 @@ namespace StardewModdingAPI.Framework.StateTracking.Snapshots
** Fields
*********/
/// <summary>A map of tracked locations.</summary>
- private readonly Dictionary<GameLocation, LocationSnapshot> LocationsDict = new Dictionary<GameLocation, LocationSnapshot>(new ObjectReferenceComparer<GameLocation>());
+ private readonly Dictionary<GameLocation, LocationSnapshot> LocationsDict = new(new ObjectReferenceComparer<GameLocation>());
/*********
** Accessors
*********/
/// <summary>Tracks changes to the location list.</summary>
- public SnapshotListDiff<GameLocation> LocationList { get; } = new SnapshotListDiff<GameLocation>();
+ public SnapshotListDiff<GameLocation> LocationList { get; } = new();
/// <summary>The tracked locations.</summary>
public IEnumerable<LocationSnapshot> Locations => this.LocationsDict.Values;
diff --git a/src/SMAPI/Framework/StateTracking/WorldLocationsTracker.cs b/src/SMAPI/Framework/StateTracking/WorldLocationsTracker.cs
index e968d79c..ab02d7d5 100644
--- a/src/SMAPI/Framework/StateTracking/WorldLocationsTracker.cs
+++ b/src/SMAPI/Framework/StateTracking/WorldLocationsTracker.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
diff --git a/src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs b/src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs
index 173438f1..5f0ecfa0 100644
--- a/src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs
+++ b/src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
// This temporary utility fixes an esoteric issue in XNA Framework where deserialization depends on
// the order of fields returned by Type.GetFields, but that order changes after Harmony/MonoMod use
// reflection to access the fields due to an issue in .NET Framework.
@@ -55,7 +57,7 @@ namespace MonoMod.Utils
.GetType("System.RuntimeType+RuntimeTypeCache")
?.GetMethod("GetPropertyList", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- private static readonly ConditionalWeakTable<Type, CacheFixEntry> _CacheFixed = new ConditionalWeakTable<Type, CacheFixEntry>();
+ private static readonly ConditionalWeakTable<Type, CacheFixEntry> _CacheFixed = new();
public static void Apply()
{
@@ -126,7 +128,7 @@ namespace MonoMod.Utils
}
public static Type GetRealDeclaringType(this MemberInfo member)
- => member.DeclaringType ?? member.Module?.GetModuleType();
+ => member.DeclaringType ?? member.Module.GetModuleType();
public static void FixReflectionCache(this Type type)
{
@@ -144,7 +146,7 @@ namespace MonoMod.Utils
continue;
CacheFixEntry entry = _CacheFixed.GetValue(type, rt => {
- CacheFixEntry entryNew = new CacheFixEntry();
+ CacheFixEntry entryNew = new();
object cache;
Array properties, fields;
diff --git a/src/SMAPI/Framework/Translator.cs b/src/SMAPI/Framework/Translator.cs
index 4492b17f..144b043c 100644
--- a/src/SMAPI/Framework/Translator.cs
+++ b/src/SMAPI/Framework/Translator.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/SMAPI/Framework/Utilities/ContextHash.cs b/src/SMAPI/Framework/Utilities/ContextHash.cs
index 6c0fdc90..46b9099e 100644
--- a/src/SMAPI/Framework/Utilities/ContextHash.cs
+++ b/src/SMAPI/Framework/Utilities/ContextHash.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
diff --git a/src/SMAPI/Framework/Utilities/Countdown.cs b/src/SMAPI/Framework/Utilities/Countdown.cs
index 342b4258..94c69e73 100644
--- a/src/SMAPI/Framework/Utilities/Countdown.cs
+++ b/src/SMAPI/Framework/Utilities/Countdown.cs
@@ -1,4 +1,4 @@
-namespace StardewModdingAPI.Framework.Utilities
+namespace StardewModdingAPI.Framework.Utilities
{
/// <summary>Counts down from a baseline value.</summary>
internal class Countdown
diff --git a/src/SMAPI/Framework/Utilities/TickCacheDictionary.cs b/src/SMAPI/Framework/Utilities/TickCacheDictionary.cs
index 1613a480..94ce0069 100644
--- a/src/SMAPI/Framework/Utilities/TickCacheDictionary.cs
+++ b/src/SMAPI/Framework/Utilities/TickCacheDictionary.cs
@@ -1,6 +1,7 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
-using StardewValley;
namespace StardewModdingAPI.Framework.Utilities
{
@@ -13,7 +14,7 @@ namespace StardewModdingAPI.Framework.Utilities
** Fields
*********/
/// <summary>The last game tick for which data was cached.</summary>
- private int LastGameTick = -1;
+ private uint? LastGameTick;
/// <summary>The underlying cached data.</summary>
private readonly Dictionary<TKey, TValue> Cache = new();
@@ -28,10 +29,10 @@ namespace StardewModdingAPI.Framework.Utilities
public TValue GetOrSet(TKey cacheKey, Func<TValue> get)
{
// clear cache on new tick
- if (Game1.ticks != this.LastGameTick)
+ if (SCore.ProcessTicksElapsed != this.LastGameTick)
{
this.Cache.Clear();
- this.LastGameTick = Game1.ticks;
+ this.LastGameTick = SCore.ProcessTicksElapsed;
}
// fetch value
diff --git a/src/SMAPI/Framework/WatcherCore.cs b/src/SMAPI/Framework/WatcherCore.cs
index 62a0c3b8..bd8d3367 100644
--- a/src/SMAPI/Framework/WatcherCore.cs
+++ b/src/SMAPI/Framework/WatcherCore.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.Xna.Framework;
@@ -17,7 +19,7 @@ namespace StardewModdingAPI.Framework
** Fields
*********/
/// <summary>The underlying watchers for convenience. These are accessible individually as separate properties.</summary>
- private readonly List<IWatcher> Watchers = new List<IWatcher>();
+ private readonly List<IWatcher> Watchers = new();
/*********
diff --git a/src/SMAPI/GamePlatform.cs b/src/SMAPI/GamePlatform.cs
index cce5ed8d..8013faa9 100644
--- a/src/SMAPI/GamePlatform.cs
+++ b/src/SMAPI/GamePlatform.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using StardewModdingAPI.Toolkit.Utilities;
namespace StardewModdingAPI
diff --git a/src/SMAPI/IAssetData.cs b/src/SMAPI/IAssetData.cs
index 8df59e53..f07340e4 100644
--- a/src/SMAPI/IAssetData.cs
+++ b/src/SMAPI/IAssetData.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI
diff --git a/src/SMAPI/IAssetDataForDictionary.cs b/src/SMAPI/IAssetDataForDictionary.cs
index 1136316f..82ba25cb 100644
--- a/src/SMAPI/IAssetDataForDictionary.cs
+++ b/src/SMAPI/IAssetDataForDictionary.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
namespace StardewModdingAPI
diff --git a/src/SMAPI/IAssetDataForImage.cs b/src/SMAPI/IAssetDataForImage.cs
index 27ed9267..388caa68 100644
--- a/src/SMAPI/IAssetDataForImage.cs
+++ b/src/SMAPI/IAssetDataForImage.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
diff --git a/src/SMAPI/IAssetDataForMap.cs b/src/SMAPI/IAssetDataForMap.cs
index 47a33de8..89ee28f2 100644
--- a/src/SMAPI/IAssetDataForMap.cs
+++ b/src/SMAPI/IAssetDataForMap.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using Microsoft.Xna.Framework;
using xTile;
diff --git a/src/SMAPI/IAssetEditor.cs b/src/SMAPI/IAssetEditor.cs
index 9f22ed83..f3d91bd0 100644
--- a/src/SMAPI/IAssetEditor.cs
+++ b/src/SMAPI/IAssetEditor.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Events;
diff --git a/src/SMAPI/IAssetInfo.cs b/src/SMAPI/IAssetInfo.cs
index 64d10b35..5b4ac479 100644
--- a/src/SMAPI/IAssetInfo.cs
+++ b/src/SMAPI/IAssetInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI
diff --git a/src/SMAPI/IAssetLoader.cs b/src/SMAPI/IAssetLoader.cs
index 96b98793..0d52a481 100644
--- a/src/SMAPI/IAssetLoader.cs
+++ b/src/SMAPI/IAssetLoader.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Events;
diff --git a/src/SMAPI/IAssetName.cs b/src/SMAPI/IAssetName.cs
index c91da266..22f5c6b7 100644
--- a/src/SMAPI/IAssetName.cs
+++ b/src/SMAPI/IAssetName.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewValley;
diff --git a/src/SMAPI/ICommandHelper.cs b/src/SMAPI/ICommandHelper.cs
index 9f1c345c..a0c524d6 100644
--- a/src/SMAPI/ICommandHelper.cs
+++ b/src/SMAPI/ICommandHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI
diff --git a/src/SMAPI/IContentHelper.cs b/src/SMAPI/IContentHelper.cs
index 48f6bfd8..0ad209ab 100644
--- a/src/SMAPI/IContentHelper.cs
+++ b/src/SMAPI/IContentHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
diff --git a/src/SMAPI/IContentPack.cs b/src/SMAPI/IContentPack.cs
index 3c66faff..f853e2b4 100644
--- a/src/SMAPI/IContentPack.cs
+++ b/src/SMAPI/IContentPack.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
diff --git a/src/SMAPI/IContentPackHelper.cs b/src/SMAPI/IContentPackHelper.cs
index c48a4f86..5464df22 100644
--- a/src/SMAPI/IContentPackHelper.cs
+++ b/src/SMAPI/IContentPackHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
namespace StardewModdingAPI
diff --git a/src/SMAPI/ICursorPosition.cs b/src/SMAPI/ICursorPosition.cs
index 99c1b84d..da6cbb62 100644
--- a/src/SMAPI/ICursorPosition.cs
+++ b/src/SMAPI/ICursorPosition.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Microsoft.Xna.Framework;
using StardewValley;
diff --git a/src/SMAPI/IDataHelper.cs b/src/SMAPI/IDataHelper.cs
index 901266d7..4c96367b 100644
--- a/src/SMAPI/IDataHelper.cs
+++ b/src/SMAPI/IDataHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI
diff --git a/src/SMAPI/IGameContentHelper.cs b/src/SMAPI/IGameContentHelper.cs
index 86bc3e0e..4b967993 100644
--- a/src/SMAPI/IGameContentHelper.cs
+++ b/src/SMAPI/IGameContentHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
diff --git a/src/SMAPI/IInputHelper.cs b/src/SMAPI/IInputHelper.cs
index 2b907b0d..b7ed0838 100644
--- a/src/SMAPI/IInputHelper.cs
+++ b/src/SMAPI/IInputHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using StardewModdingAPI.Utilities;
namespace StardewModdingAPI
diff --git a/src/SMAPI/IMod.cs b/src/SMAPI/IMod.cs
index 44ef32c9..0de4961e 100644
--- a/src/SMAPI/IMod.cs
+++ b/src/SMAPI/IMod.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI
{
/// <summary>The implementation for a Stardew Valley mod.</summary>
diff --git a/src/SMAPI/IModContentHelper.cs b/src/SMAPI/IModContentHelper.cs
index e3431365..815d6848 100644
--- a/src/SMAPI/IModContentHelper.cs
+++ b/src/SMAPI/IModContentHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
diff --git a/src/SMAPI/IModHelper.cs b/src/SMAPI/IModHelper.cs
index 15e4ed8d..5e4246aa 100644
--- a/src/SMAPI/IModHelper.cs
+++ b/src/SMAPI/IModHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using StardewModdingAPI.Events;
diff --git a/src/SMAPI/IModInfo.cs b/src/SMAPI/IModInfo.cs
index 3c85d454..2788e4fc 100644
--- a/src/SMAPI/IModInfo.cs
+++ b/src/SMAPI/IModInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI
{
/// <summary>Metadata for a loaded mod.</summary>
diff --git a/src/SMAPI/IModLinked.cs b/src/SMAPI/IModLinked.cs
index 172ee30c..cf08c9c5 100644
--- a/src/SMAPI/IModLinked.cs
+++ b/src/SMAPI/IModLinked.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI
{
/// <summary>An instance linked to a mod.</summary>
diff --git a/src/SMAPI/IModRegistry.cs b/src/SMAPI/IModRegistry.cs
index 10b3121e..9cab08a1 100644
--- a/src/SMAPI/IModRegistry.cs
+++ b/src/SMAPI/IModRegistry.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
namespace StardewModdingAPI
diff --git a/src/SMAPI/IMonitor.cs b/src/SMAPI/IMonitor.cs
index c400a211..535f56e3 100644
--- a/src/SMAPI/IMonitor.cs
+++ b/src/SMAPI/IMonitor.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI
{
/// <summary>Encapsulates monitoring and logging for a given module.</summary>
diff --git a/src/SMAPI/IMultiplayerHelper.cs b/src/SMAPI/IMultiplayerHelper.cs
index 4067a676..77a0f3f4 100644
--- a/src/SMAPI/IMultiplayerHelper.cs
+++ b/src/SMAPI/IMultiplayerHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using StardewValley;
diff --git a/src/SMAPI/IMultiplayerPeer.cs b/src/SMAPI/IMultiplayerPeer.cs
index 47084174..e487f100 100644
--- a/src/SMAPI/IMultiplayerPeer.cs
+++ b/src/SMAPI/IMultiplayerPeer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
namespace StardewModdingAPI
diff --git a/src/SMAPI/IMultiplayerPeerMod.cs b/src/SMAPI/IMultiplayerPeerMod.cs
index 005408b1..81978bef 100644
--- a/src/SMAPI/IMultiplayerPeerMod.cs
+++ b/src/SMAPI/IMultiplayerPeerMod.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace StardewModdingAPI
{
/// <summary>Metadata about a mod installed by a connected player.</summary>
diff --git a/src/SMAPI/IReflectedField.cs b/src/SMAPI/IReflectedField.cs
index 7ff61f29..94dbe6a3 100644
--- a/src/SMAPI/IReflectedField.cs
+++ b/src/SMAPI/IReflectedField.cs
@@ -1,4 +1,6 @@
-using System.Reflection;
+#nullable disable
+
+using System.Reflection;
namespace StardewModdingAPI
{
diff --git a/src/SMAPI/IReflectedMethod.cs b/src/SMAPI/IReflectedMethod.cs
index 646e7301..78e66cb1 100644
--- a/src/SMAPI/IReflectedMethod.cs
+++ b/src/SMAPI/IReflectedMethod.cs
@@ -1,4 +1,6 @@
-using System.Reflection;
+#nullable disable
+
+using System.Reflection;
namespace StardewModdingAPI
{
diff --git a/src/SMAPI/IReflectedProperty.cs b/src/SMAPI/IReflectedProperty.cs
index 73ad9f30..edbf0b21 100644
--- a/src/SMAPI/IReflectedProperty.cs
+++ b/src/SMAPI/IReflectedProperty.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Reflection;
namespace StardewModdingAPI
diff --git a/src/SMAPI/IReflectionHelper.cs b/src/SMAPI/IReflectionHelper.cs
index a2b9eb32..bf7270cf 100644
--- a/src/SMAPI/IReflectionHelper.cs
+++ b/src/SMAPI/IReflectionHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI
diff --git a/src/SMAPI/ITranslationHelper.cs b/src/SMAPI/ITranslationHelper.cs
index b30d9b14..3c297731 100644
--- a/src/SMAPI/ITranslationHelper.cs
+++ b/src/SMAPI/ITranslationHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using StardewValley;
diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs
index 424abc18..b7cec72c 100644
--- a/src/SMAPI/Metadata/CoreAssetPropagator.cs
+++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
@@ -1238,6 +1240,9 @@ namespace StardewModdingAPI.Metadata
/// <param name="right">The second value to compare.</param>
private bool IsSameBaseName(IAssetName left, string right)
{
+ if (left is null || right is null)
+ return false;
+
IAssetName parsedB = this.ParseAssetNameOrNull(right);
return this.IsSameBaseName(left, parsedB);
}
@@ -1247,6 +1252,9 @@ namespace StardewModdingAPI.Metadata
/// <param name="right">The second value to compare.</param>
private bool IsSameBaseName(IAssetName left, IAssetName right)
{
+ if (left is null || right is null)
+ return false;
+
return left.IsEquivalentTo(right.BaseName, useBaseName: true);
}
diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs
index 367372b2..5617fd13 100644
--- a/src/SMAPI/Metadata/InstructionMetadata.cs
+++ b/src/SMAPI/Metadata/InstructionMetadata.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI.Events;
diff --git a/src/SMAPI/Mod.cs b/src/SMAPI/Mod.cs
index 9af55cd4..2b3750d5 100644
--- a/src/SMAPI/Mod.cs
+++ b/src/SMAPI/Mod.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace StardewModdingAPI
diff --git a/src/SMAPI/Patches/Game1Patcher.cs b/src/SMAPI/Patches/Game1Patcher.cs
index 173a2055..c5d98e9e 100644
--- a/src/SMAPI/Patches/Game1Patcher.cs
+++ b/src/SMAPI/Patches/Game1Patcher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Diagnostics.CodeAnalysis;
using HarmonyLib;
diff --git a/src/SMAPI/Patches/TitleMenuPatcher.cs b/src/SMAPI/Patches/TitleMenuPatcher.cs
index b4320ce0..56e5597c 100644
--- a/src/SMAPI/Patches/TitleMenuPatcher.cs
+++ b/src/SMAPI/Patches/TitleMenuPatcher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Diagnostics.CodeAnalysis;
using HarmonyLib;
diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs
index 1e3b2000..0c9c2d87 100644
--- a/src/SMAPI/Program.cs
+++ b/src/SMAPI/Program.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.IO;
@@ -78,7 +80,7 @@ namespace StardewModdingAPI
}
catch
{
- continue;
+ // ignore invalid DLL
}
}
}
@@ -206,7 +208,7 @@ namespace StardewModdingAPI
}
// load SMAPI
- using SCore core = new SCore(modsPath, writeToConsole, developerMode);
+ using SCore core = new(modsPath, writeToConsole, developerMode);
core.RunInteractively();
}
diff --git a/src/SMAPI/SButton.cs b/src/SMAPI/SButton.cs
index ae825696..133ea901 100644
--- a/src/SMAPI/SButton.cs
+++ b/src/SMAPI/SButton.cs
@@ -674,7 +674,7 @@ namespace StardewModdingAPI
}
// mouse
- if (input == SButton.MouseLeft || input == SButton.MouseRight)
+ if (input is SButton.MouseLeft or SButton.MouseRight)
{
button = new InputButton(mouseLeft: input == SButton.MouseLeft);
return true;
diff --git a/src/SMAPI/SButtonState.cs b/src/SMAPI/SButtonState.cs
index 5f3e8d3c..ca2dd83d 100644
--- a/src/SMAPI/SButtonState.cs
+++ b/src/SMAPI/SButtonState.cs
@@ -23,7 +23,7 @@ namespace StardewModdingAPI
/// <param name="state">The button state.</param>
public static bool IsDown(this SButtonState state)
{
- return state == SButtonState.Held || state == SButtonState.Pressed;
+ return state is SButtonState.Held or SButtonState.Pressed;
}
}
}
diff --git a/src/SMAPI/SMAPI.config.json b/src/SMAPI/SMAPI.config.json
index e62c8880..49056e83 100644
--- a/src/SMAPI/SMAPI.config.json
+++ b/src/SMAPI/SMAPI.config.json
@@ -70,11 +70,6 @@ copy all the settings, or you may cause bugs due to overridden changes in future
"GitHubProjectName": "Pathoschild/SMAPI",
/**
- * Stardew64Installer's GitHub project name, used to perform update checks.
- */
- "Stardew64InstallerGitHubProjectName": "Steviegt6/Stardew64Installer",
-
- /**
* The base URL for SMAPI's web API, used to perform update checks.
*/
"WebApiBaseUrl": "https://smapi.io/api/",
diff --git a/src/SMAPI/SemanticVersion.cs b/src/SMAPI/SemanticVersion.cs
index ae616419..7a6cdcdd 100644
--- a/src/SMAPI/SemanticVersion.cs
+++ b/src/SMAPI/SemanticVersion.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json;
namespace StardewModdingAPI
@@ -26,10 +27,10 @@ namespace StardewModdingAPI
public int PatchVersion => this.Version.PatchVersion;
/// <inheritdoc />
- public string PrereleaseTag => this.Version.PrereleaseTag;
+ public string? PrereleaseTag => this.Version.PrereleaseTag;
/// <inheritdoc />
- public string BuildMetadata => this.Version.BuildMetadata;
+ public string? BuildMetadata => this.Version.BuildMetadata;
/*********
@@ -41,7 +42,7 @@ namespace StardewModdingAPI
/// <param name="patchVersion">The patch version for backwards-compatible bug fixes.</param>
/// <param name="prereleaseTag">An optional prerelease tag.</param>
/// <param name="buildMetadata">Optional build metadata. This is ignored when determining version precedence.</param>
- public SemanticVersion(int majorVersion, int minorVersion, int patchVersion, string prereleaseTag = null, string buildMetadata = null)
+ public SemanticVersion(int majorVersion, int minorVersion, int patchVersion, string? prereleaseTag = null, string? buildMetadata = null)
: this(majorVersion, minorVersion, patchVersion, 0, prereleaseTag, buildMetadata) { }
/// <summary>Construct an instance.</summary>
@@ -52,7 +53,7 @@ namespace StardewModdingAPI
/// <param name="platformRelease">The platform-specific version (if applicable).</param>
/// <param name="buildMetadata">Optional build metadata. This is ignored when determining version precedence.</param>
[JsonConstructor]
- internal SemanticVersion(int majorVersion, int minorVersion, int patchVersion, int platformRelease, string prereleaseTag = null, string buildMetadata = null)
+ internal SemanticVersion(int majorVersion, int minorVersion, int patchVersion, int platformRelease, string? prereleaseTag = null, string? buildMetadata = null)
: this(new Toolkit.SemanticVersion(majorVersion, minorVersion, patchVersion, platformRelease, prereleaseTag, buildMetadata)) { }
/// <summary>Construct an instance.</summary>
@@ -91,49 +92,49 @@ namespace StardewModdingAPI
/// <inheritdoc />
/// <remarks>The implementation is defined by Semantic Version 2.0 (https://semver.org/).</remarks>
- public int CompareTo(ISemanticVersion other)
+ public int CompareTo(ISemanticVersion? other)
{
return this.Version.CompareTo(other);
}
/// <inheritdoc />
- public bool IsOlderThan(ISemanticVersion other)
+ public bool IsOlderThan(ISemanticVersion? other)
{
return this.Version.IsOlderThan(other);
}
/// <inheritdoc />
- public bool IsOlderThan(string other)
+ public bool IsOlderThan(string? other)
{
return this.Version.IsOlderThan(other);
}
/// <inheritdoc />
- public bool IsNewerThan(ISemanticVersion other)
+ public bool IsNewerThan(ISemanticVersion? other)
{
return this.Version.IsNewerThan(other);
}
/// <inheritdoc />
- public bool IsNewerThan(string other)
+ public bool IsNewerThan(string? other)
{
return this.Version.IsNewerThan(other);
}
/// <inheritdoc />
- public bool IsBetween(ISemanticVersion min, ISemanticVersion max)
+ public bool IsBetween(ISemanticVersion? min, ISemanticVersion? max)
{
return this.Version.IsBetween(min, max);
}
/// <inheritdoc />
- public bool IsBetween(string min, string max)
+ public bool IsBetween(string? min, string? max)
{
return this.Version.IsBetween(min, max);
}
/// <inheritdoc />
- public bool Equals(ISemanticVersion other)
+ public bool Equals(ISemanticVersion? other)
{
return other != null && this.CompareTo(other) == 0;
}
@@ -154,9 +155,9 @@ namespace StardewModdingAPI
/// <param name="version">The version string.</param>
/// <param name="parsed">The parsed representation.</param>
/// <returns>Returns whether parsing the version succeeded.</returns>
- public static bool TryParse(string version, out ISemanticVersion parsed)
+ public static bool TryParse(string version, [NotNullWhen(true)] out ISemanticVersion? parsed)
{
- if (Toolkit.SemanticVersion.TryParse(version, out ISemanticVersion versionImpl))
+ if (Toolkit.SemanticVersion.TryParse(version, out ISemanticVersion? versionImpl))
{
parsed = new SemanticVersion(versionImpl);
return true;
diff --git a/src/SMAPI/Translation.cs b/src/SMAPI/Translation.cs
index 149f6728..ef98a00f 100644
--- a/src/SMAPI/Translation.cs
+++ b/src/SMAPI/Translation.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections;
using System.Collections.Generic;
@@ -74,7 +76,7 @@ namespace StardewModdingAPI
{
foreach (DictionaryEntry entry in inputLookup)
{
- string key = entry.Key?.ToString().Trim();
+ string key = entry.Key.ToString()?.Trim();
if (key != null)
tokenLookup[key] = entry.Value?.ToString();
}
diff --git a/src/SMAPI/Utilities/CaseInsensitivePathCache.cs b/src/SMAPI/Utilities/CaseInsensitivePathCache.cs
new file mode 100644
index 00000000..4596fdce
--- /dev/null
+++ b/src/SMAPI/Utilities/CaseInsensitivePathCache.cs
@@ -0,0 +1,126 @@
+#nullable disable
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace StardewModdingAPI.Utilities
+{
+ /// <summary>Provides an API for case-insensitive relative path lookups within a root directory.</summary>
+ internal class CaseInsensitivePathCache
+ {
+ /*********
+ ** Fields
+ *********/
+ /// <summary>The root directory path for relative paths.</summary>
+ private readonly string RootPath;
+
+ /// <summary>A case-insensitive lookup of file paths within the <see cref="RootPath"/>. Each path is listed in both file path and asset name format, so it's usable in both contexts without needing to re-parse paths.</summary>
+ private readonly Lazy<Dictionary<string, string>> RelativePathCache;
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="rootPath">The root directory path for relative paths.</param>
+ public CaseInsensitivePathCache(string rootPath)
+ {
+ this.RootPath = rootPath;
+ this.RelativePathCache = new(this.GetRelativePathCache);
+ }
+
+ /// <summary>Get the exact capitalization for a given relative file path.</summary>
+ /// <param name="relativePath">The relative path.</param>
+ /// <remarks>Returns the resolved path in file path format, else the normalized <paramref name="relativePath"/>.</remarks>
+ public string GetFilePath(string relativePath)
+ {
+ return this.GetImpl(PathUtilities.NormalizePath(relativePath));
+ }
+
+ /// <summary>Get the exact capitalization for a given asset name.</summary>
+ /// <param name="relativePath">The relative path.</param>
+ /// <remarks>Returns the resolved path in asset name format, else the normalized <paramref name="relativePath"/>.</remarks>
+ public string GetAssetName(string relativePath)
+ {
+ return this.GetImpl(PathUtilities.NormalizeAssetName(relativePath));
+ }
+
+ /// <summary>Add a relative path that was just created by a SMAPI API.</summary>
+ /// <param name="relativePath">The relative path. This must already be normalized in asset name or file path format.</param>
+ public void Add(string relativePath)
+ {
+ // skip if cache isn't created yet (no need to add files manually in that case)
+ if (!this.RelativePathCache.IsValueCreated)
+ return;
+
+ // skip if already cached
+ if (this.RelativePathCache.Value.ContainsKey(relativePath))
+ return;
+
+ // make sure path exists
+ relativePath = PathUtilities.NormalizePath(relativePath);
+ if (!File.Exists(Path.Combine(this.RootPath, relativePath)))
+ throw new InvalidOperationException($"Can't add relative path '{relativePath}' to the case-insensitive cache for '{this.RootPath}' because that file doesn't exist.");
+
+ // cache path
+ this.CacheRawPath(this.RelativePathCache.Value, relativePath);
+ }
+
+
+ /*********
+ ** Private methods
+ *********/
+ /// <summary>Get the exact capitalization for a given relative path.</summary>
+ /// <param name="relativePath">The relative path. This must already be normalized into asset name or file path format (i.e. using <see cref="PathUtilities.NormalizeAssetName"/> or <see cref="PathUtilities.NormalizePath"/> respectively).</param>
+ /// <remarks>Returns the resolved path in the same format if found, else returns the path as-is.</remarks>
+ private string GetImpl(string relativePath)
+ {
+ // invalid path
+ if (string.IsNullOrWhiteSpace(relativePath))
+ return relativePath;
+
+ // already cached
+ if (this.RelativePathCache.Value.TryGetValue(relativePath, out string resolved))
+ return resolved;
+
+ // file exists but isn't cached for some reason
+ // cache it now so any later references to it are case-insensitive
+ if (File.Exists(Path.Combine(this.RootPath, relativePath)))
+ {
+ this.CacheRawPath(this.RelativePathCache.Value, relativePath);
+ return relativePath;
+ }
+
+ // no such file, keep capitalization as-is
+ return relativePath;
+ }
+
+ /// <summary>Get a case-insensitive lookup of file paths (see <see cref="RelativePathCache"/>).</summary>
+ private Dictionary<string, string> GetRelativePathCache()
+ {
+ Dictionary<string, string> cache = new(StringComparer.OrdinalIgnoreCase);
+
+ foreach (string path in Directory.EnumerateFiles(this.RootPath, "*", SearchOption.AllDirectories))
+ {
+ string relativePath = path.Substring(this.RootPath.Length + 1);
+
+ this.CacheRawPath(cache, relativePath);
+ }
+
+ return cache;
+ }
+
+ /// <summary>Add a raw relative path to the cache.</summary>
+ /// <param name="cache">The cache to update.</param>
+ /// <param name="relativePath">The relative path to cache, with its exact filesystem capitalization.</param>
+ private void CacheRawPath(IDictionary<string, string> cache, string relativePath)
+ {
+ string filePath = PathUtilities.NormalizePath(relativePath);
+ string assetName = PathUtilities.NormalizeAssetName(relativePath);
+
+ cache[filePath] = filePath;
+ cache[assetName] = assetName;
+ }
+ }
+}
diff --git a/src/SMAPI/Utilities/Keybind.cs b/src/SMAPI/Utilities/Keybind.cs
index 403ecf4a..7b1acf1d 100644
--- a/src/SMAPI/Utilities/Keybind.cs
+++ b/src/SMAPI/Utilities/Keybind.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -118,11 +120,11 @@ namespace StardewModdingAPI.Utilities
return SButtonState.None;
// mix of held + pressed => pressed
- if (states.All(p => p == SButtonState.Pressed || p == SButtonState.Held))
+ if (states.All(p => p is SButtonState.Pressed or SButtonState.Held))
return SButtonState.Pressed;
// mix of held + released => released
- if (states.All(p => p == SButtonState.Held || p == SButtonState.Released))
+ if (states.All(p => p is SButtonState.Held or SButtonState.Released))
return SButtonState.Released;
// not down last tick or now
diff --git a/src/SMAPI/Utilities/KeybindList.cs b/src/SMAPI/Utilities/KeybindList.cs
index f8f569af..7b2c396b 100644
--- a/src/SMAPI/Utilities/KeybindList.cs
+++ b/src/SMAPI/Utilities/KeybindList.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -139,7 +141,7 @@ namespace StardewModdingAPI.Utilities
public bool IsDown()
{
SButtonState state = this.GetState();
- return state == SButtonState.Pressed || state == SButtonState.Held;
+ return state is SButtonState.Pressed or SButtonState.Held;
}
/// <summary>Get whether the input binding was just pressed this tick.</summary>
diff --git a/src/SMAPI/Utilities/PathUtilities.cs b/src/SMAPI/Utilities/PathUtilities.cs
index 541b163c..4350f441 100644
--- a/src/SMAPI/Utilities/PathUtilities.cs
+++ b/src/SMAPI/Utilities/PathUtilities.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using ToolkitPathUtilities = StardewModdingAPI.Toolkit.Utilities.PathUtilities;
@@ -20,14 +21,16 @@ namespace StardewModdingAPI.Utilities
/// <param name="path">The path to split.</param>
/// <param name="limit">The number of segments to match. Any additional segments will be merged into the last returned part.</param>
[Pure]
- public static string[] GetSegments(string path, int? limit = null)
+ public static string[] GetSegments(string? path, int? limit = null)
{
return ToolkitPathUtilities.GetSegments(path, limit);
}
/// <summary>Normalize an asset name to match how MonoGame's content APIs would normalize and cache it.</summary>
/// <param name="assetName">The asset name to normalize.</param>
- public static string NormalizeAssetName(string assetName)
+ [Pure]
+ [return: NotNullIfNotNull("assetName")]
+ public static string? NormalizeAssetName(string? assetName)
{
return ToolkitPathUtilities.NormalizeAssetName(assetName);
}
@@ -36,7 +39,8 @@ namespace StardewModdingAPI.Utilities
/// <param name="path">The file path to normalize.</param>
/// <remarks>This should only be used for file paths. For asset names, use <see cref="NormalizeAssetName"/> instead.</remarks>
[Pure]
- public static string NormalizePath(string path)
+ [return: NotNullIfNotNull("path")]
+ public static string? NormalizePath(string? path)
{
return ToolkitPathUtilities.NormalizePath(path);
}
@@ -44,7 +48,7 @@ namespace StardewModdingAPI.Utilities
/// <summary>Get whether a path is relative and doesn't try to climb out of its containing folder (e.g. doesn't contain <c>../</c>).</summary>
/// <param name="path">The path to check.</param>
[Pure]
- public static bool IsSafeRelativePath(string path)
+ public static bool IsSafeRelativePath(string? path)
{
return ToolkitPathUtilities.IsSafeRelativePath(path);
}
@@ -52,7 +56,7 @@ namespace StardewModdingAPI.Utilities
/// <summary>Get whether a string is a valid 'slug', containing only basic characters that are safe in all contexts (e.g. filenames, URLs, etc).</summary>
/// <param name="str">The string to check.</param>
[Pure]
- public static bool IsSlug(string str)
+ public static bool IsSlug(string? str)
{
return ToolkitPathUtilities.IsSlug(str);
}
diff --git a/src/SMAPI/Utilities/PerScreen.cs b/src/SMAPI/Utilities/PerScreen.cs
index 20b8fbce..afe3ba91 100644
--- a/src/SMAPI/Utilities/PerScreen.cs
+++ b/src/SMAPI/Utilities/PerScreen.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -76,7 +78,7 @@ namespace StardewModdingAPI.Utilities
/// <summary>Remove all active values.</summary>
public void ResetAllScreens()
{
- this.RemoveScreens(p => true);
+ this.RemoveScreens(_ => true);
}
diff --git a/src/SMAPI/Utilities/SDate.cs b/src/SMAPI/Utilities/SDate.cs
index e10a59f8..b10bc3da 100644
--- a/src/SMAPI/Utilities/SDate.cs
+++ b/src/SMAPI/Utilities/SDate.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Linq;
using Newtonsoft.Json;