diff --git a/docs/release-notes.md b/docs/release-notes.md index b22f4de9..7fff656a 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -3,11 +3,10 @@ # Release notes ## Upcoming release * For players: - * Added experimental image load rewrite (disabled by default). - _If you have many content mods installed, enabling `UseExperimentalImageLoading` in `smapi-internal/config.json` may reduce load times or stutters when they load many image files at once._ + * Optimized mod image file loading. * For mod authors: - * Added specialized `IRawTextureData` asset type. - _When you're only loading a mod file to patch it into an asset, you can now load it using `helper.ModContent.Load(path)`. This reads the image data from disk without initializing a `Texture2D` instance through the GPU. You can then pass this to SMAPI APIs that accept `Texture2D` instances._ + * Added a new `IRawTextureData` asset type. + _You can now load image files through `helper.ModContent` as `IRawTextureData` instead of `Texture2D`. This provides the image size and raw pixel data, which you can pass into other SMAPI APIs like `asset.AsImage().PatchImage`. This is much more efficient when you don't need a full `Texture2D` instance, since it bypasses the GPU operations needed to create one._ * For mod authors: * Fixed map edits which change warps sometimes rebuilding the NPC pathfinding cache unnecessarily, which could cause a noticeable delay for players. diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs index 3ad112cd..3e09ac62 100644 --- a/src/SMAPI/Framework/ContentCoordinator.cs +++ b/src/SMAPI/Framework/ContentCoordinator.cs @@ -32,8 +32,8 @@ namespace StardewModdingAPI.Framework /// An asset key prefix for assets from SMAPI mod folders. private readonly string ManagedPrefix = "SMAPI"; - /// Whether to use a newer approach when loading image files from mod folder which may be faster. - private readonly bool UseExperimentalImageLoading; + /// Whether to use raw image data when possible, instead of initializing an XNA Texture2D instance through the GPU. + private readonly bool UseRawImageLoading; /// Get a file lookup for the given directory. private readonly Func GetFileLookup; @@ -133,8 +133,8 @@ namespace StardewModdingAPI.Framework /// Get a file lookup for the given directory. /// A callback to invoke when any asset names have been invalidated from the cache. /// Get the load/edit operations to apply to an asset by querying registered event handlers. - /// Whether to use a newer approach when loading image files from mod folder which may be faster. - public ContentCoordinator(IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, IMonitor monitor, Reflector reflection, JsonHelper jsonHelper, Action onLoadingFirstAsset, Action onAssetLoaded, Func getFileLookup, Action> onAssetsInvalidated, Func requestAssetOperations, bool useExperimentalImageLoading) + /// Whether to use raw image data when possible, instead of initializing an XNA Texture2D instance through the GPU. + public ContentCoordinator(IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, IMonitor monitor, Reflector reflection, JsonHelper jsonHelper, Action onLoadingFirstAsset, Action onAssetLoaded, Func getFileLookup, Action> onAssetsInvalidated, Func requestAssetOperations, bool useRawImageLoading) { this.GetFileLookup = getFileLookup; this.Monitor = monitor ?? throw new ArgumentNullException(nameof(monitor)); @@ -145,7 +145,7 @@ namespace StardewModdingAPI.Framework this.OnAssetsInvalidated = onAssetsInvalidated; this.RequestAssetOperations = requestAssetOperations; this.FullRootDirectory = Path.Combine(Constants.GamePath, rootDirectory); - this.UseExperimentalImageLoading = useExperimentalImageLoading; + this.UseRawImageLoading = useRawImageLoading; this.ContentManagers.Add( this.MainContentManager = new GameContentManager( name: "Game1.content", @@ -225,7 +225,7 @@ namespace StardewModdingAPI.Framework jsonHelper: this.JsonHelper, onDisposing: this.OnDisposing, fileLookup: this.GetFileLookup(rootDirectory), - useExperimentalImageLoading: this.UseExperimentalImageLoading + useRawImageLoading: this.UseRawImageLoading ); this.ContentManagers.Add(manager); return manager; diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs index eb4f4555..f0e9b1b9 100644 --- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs @@ -27,8 +27,8 @@ namespace StardewModdingAPI.Framework.ContentManagers /********* ** Fields *********/ - /// Whether to use a newer approach when loading image files from mod folder which may be faster. - private readonly bool UseExperimentalImageLoading; + /// Whether to use raw image data when possible, instead of initializing an XNA Texture2D instance through the GPU. + private readonly bool UseRawImageLoading; /// Encapsulates SMAPI's JSON file parsing. private readonly JsonHelper JsonHelper; @@ -62,15 +62,15 @@ namespace StardewModdingAPI.Framework.ContentManagers /// Encapsulates SMAPI's JSON file parsing. /// A callback to invoke when the content manager is being disposed. /// A lookup for files within the . - /// Whether to use a newer approach when loading image files from mod folder which may be faster. - public ModContentManager(string name, IContentManager gameContentManager, IServiceProvider serviceProvider, string modName, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, JsonHelper jsonHelper, Action onDisposing, IFileLookup fileLookup, bool useExperimentalImageLoading) + /// Whether to use raw image data when possible, instead of initializing an XNA Texture2D instance through the GPU. + public ModContentManager(string name, IContentManager gameContentManager, IServiceProvider serviceProvider, string modName, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, JsonHelper jsonHelper, Action onDisposing, IFileLookup fileLookup, bool useRawImageLoading) : base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, isNamespaced: true) { this.GameContentManager = gameContentManager; this.FileLookup = fileLookup; this.JsonHelper = jsonHelper; this.ModName = modName; - this.UseExperimentalImageLoading = useExperimentalImageLoading; + this.UseRawImageLoading = useRawImageLoading; this.TryLocalizeKeys = false; } @@ -199,7 +199,7 @@ namespace StardewModdingAPI.Framework.ContentManagers } // load - if (asRawData || this.UseExperimentalImageLoading) + if (asRawData || this.UseRawImageLoading) { // load raw data using FileStream stream = File.OpenRead(file.FullName); diff --git a/src/SMAPI/Framework/Models/SConfig.cs b/src/SMAPI/Framework/Models/SConfig.cs index f12da0a7..6edaa818 100644 --- a/src/SMAPI/Framework/Models/SConfig.cs +++ b/src/SMAPI/Framework/Models/SConfig.cs @@ -23,7 +23,7 @@ namespace StardewModdingAPI.Framework.Models [nameof(LogNetworkTraffic)] = false, [nameof(RewriteMods)] = true, [nameof(UsePintail)] = true, - [nameof(UseExperimentalImageLoading)] = false, + [nameof(UseRawImageLoading)] = true, [nameof(UseCaseInsensitivePaths)] = Constants.Platform is Platform.Android or Platform.Linux }; @@ -67,8 +67,8 @@ namespace StardewModdingAPI.Framework.Models /// Whether to use the experimental Pintail API proxying library, instead of the original proxying built into SMAPI itself. public bool UsePintail { get; } - /// Whether to use a newer approach when loading image files from mod folder which may be faster. - public bool UseExperimentalImageLoading { get; } + /// Whether to use raw image data when possible, instead of initializing an XNA Texture2D instance through the GPU. + public bool UseRawImageLoading { get; } /// Whether to make SMAPI file APIs case-insensitive, even on Linux. public bool UseCaseInsensitivePaths { get; } @@ -96,12 +96,12 @@ namespace StardewModdingAPI.Framework.Models /// The log contexts for which to enable verbose logging, which may show a lot more information to simplify troubleshooting. /// Whether SMAPI should rewrite mods for compatibility. /// Whether to use the experimental Pintail API proxying library, instead of the original proxying built into SMAPI itself. - /// Whether to use a newer approach when loading image files from mod folder which may be faster. + /// Whether to use raw image data when possible, instead of initializing an XNA Texture2D instance through the GPU. /// >Whether to make SMAPI file APIs case-insensitive, even on Linux. /// Whether SMAPI should log network traffic. /// The colors to use for text written to the SMAPI console. /// The mod IDs SMAPI should ignore when performing update checks or validating update keys. - public SConfig(bool developerMode, bool? checkForUpdates, bool? paranoidWarnings, bool? useBetaChannel, string gitHubProjectName, string webApiBaseUrl, string[]? verboseLogging, bool? rewriteMods, bool? usePintail, bool? useExperimentalImageLoading, bool? useCaseInsensitivePaths, bool? logNetworkTraffic, ColorSchemeConfig consoleColors, string[]? suppressUpdateChecks) + public SConfig(bool developerMode, bool? checkForUpdates, bool? paranoidWarnings, bool? useBetaChannel, string gitHubProjectName, string webApiBaseUrl, string[]? verboseLogging, bool? rewriteMods, bool? usePintail, bool? useRawImageLoading, bool? useCaseInsensitivePaths, bool? logNetworkTraffic, ColorSchemeConfig consoleColors, string[]? suppressUpdateChecks) { this.DeveloperMode = developerMode; this.CheckForUpdates = checkForUpdates ?? (bool)SConfig.DefaultValues[nameof(this.CheckForUpdates)]; @@ -112,7 +112,7 @@ namespace StardewModdingAPI.Framework.Models this.VerboseLogging = new HashSet(verboseLogging ?? Array.Empty(), StringComparer.OrdinalIgnoreCase); this.RewriteMods = rewriteMods ?? (bool)SConfig.DefaultValues[nameof(this.RewriteMods)]; this.UsePintail = usePintail ?? (bool)SConfig.DefaultValues[nameof(this.UsePintail)]; - this.UseExperimentalImageLoading = useExperimentalImageLoading ?? (bool)SConfig.DefaultValues[nameof(this.UseExperimentalImageLoading)]; + this.UseRawImageLoading = useRawImageLoading ?? (bool)SConfig.DefaultValues[nameof(this.UseRawImageLoading)]; this.UseCaseInsensitivePaths = useCaseInsensitivePaths ?? (bool)SConfig.DefaultValues[nameof(this.UseCaseInsensitivePaths)]; this.LogNetworkTraffic = logNetworkTraffic ?? (bool)SConfig.DefaultValues[nameof(this.LogNetworkTraffic)]; this.ConsoleColors = consoleColors; diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 242776b3..f018acad 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -1302,7 +1302,7 @@ namespace StardewModdingAPI.Framework onAssetsInvalidated: this.OnAssetsInvalidated, getFileLookup: this.GetFileLookup, requestAssetOperations: this.RequestAssetOperations, - useExperimentalImageLoading: this.Settings.UseExperimentalImageLoading + useRawImageLoading: this.Settings.UseRawImageLoading ); if (this.ContentCore.Language != this.Translator.LocaleEnum) this.Translator.SetLocale(this.ContentCore.GetLocale(), this.ContentCore.Language); diff --git a/src/SMAPI/SMAPI.config.json b/src/SMAPI/SMAPI.config.json index 8e710435..97e8e00c 100644 --- a/src/SMAPI/SMAPI.config.json +++ b/src/SMAPI/SMAPI.config.json @@ -61,9 +61,10 @@ copy all the settings, or you may cause bugs due to overridden changes in future "UsePintail": true, /** - * Whether to use a newer approach when loading image files from mod folder which may be faster. + * Whether to use raw image data when possible, instead of initializing an XNA Texture2D + * instance through the GPU. */ - "UseExperimentalImageLoading": false, + "UseRawImageLoading": true, /** * Whether to add a section to the 'mod issues' list for mods which directly use potentially