diff --git a/src/SMAPI/Framework/Content/AssetDataForImage.cs b/src/SMAPI/Framework/Content/AssetDataForImage.cs index 5016bcd4..5f175217 100644 --- a/src/SMAPI/Framework/Content/AssetDataForImage.cs +++ b/src/SMAPI/Framework/Content/AssetDataForImage.cs @@ -40,7 +40,7 @@ namespace StardewModdingAPI.Framework.Content this.GetPatchBounds(ref sourceArea, ref targetArea, source.Width, source.Height); // get the pixels for the source area - Color[] trimmedSourceData; + Color[] sourceData; { int areaX = sourceArea.Value.X; int areaY = sourceArea.Value.Y; @@ -49,42 +49,40 @@ namespace StardewModdingAPI.Framework.Content if (areaX == 0 && areaY == 0 && areaWidth == source.Width && areaHeight == source.Height) { - trimmedSourceData = source.Data; - this.PatchImageImpl(trimmedSourceData, source.Width, source.Height, sourceArea.Value, targetArea.Value, patchMode); + sourceData = source.Data; + this.PatchImageImpl(sourceData, source.Width, source.Height, sourceArea.Value, targetArea.Value, patchMode); } else { int pixelCount = areaWidth * areaHeight; - trimmedSourceData = ArrayPool.Shared.Rent(pixelCount); + sourceData = ArrayPool.Shared.Rent(pixelCount); - // shortcut! If I want a horizontal slice of the texture - // I can copy the whole array in one pass - // Likely ~uncommon but Array.Copy significantly benefits - // from being able to do this. - if (areaWidth == source.Width && areaX == 0) + if (areaX == 0 && areaWidth == source.Width) { - int sourceIndex = areaY * source.Width; - int targetIndex = 0; + // shortcut copying because the area to copy is contiguous. This is + // probably uncommon, but Array.Copy benefits a lot. + + int sourceIndex = areaY * areaWidth; + int targetIndex = 0; + Array.Copy(source.Data, sourceIndex, sourceData, targetIndex, areaWidth); - Array.Copy(source.Data, sourceIndex, trimmedSourceData, targetIndex, pixelCount); } else { - // copying line-by-line - // Array.Copy isn't great at small scale + // slower copying, line by line for (int y = areaY, maxY = areaY + areaHeight; y < maxY; y++) { int sourceIndex = (y * source.Width) + areaX; int targetIndex = (y - areaY) * areaWidth; - Array.Copy(source.Data, sourceIndex, trimmedSourceData, targetIndex, areaWidth); + Array.Copy(source.Data, sourceIndex, sourceData, targetIndex, areaWidth); } } // apply - this.PatchImageImpl(trimmedSourceData, source.Width, source.Height, sourceArea.Value, targetArea.Value, patchMode); + this.PatchImageImpl(sourceData, source.Width, source.Height, sourceArea.Value, targetArea.Value, patchMode); // return - ArrayPool.Shared.Return(trimmedSourceData); + ArrayPool.Shared.Return(sourceData); } } } @@ -176,9 +174,9 @@ namespace StardewModdingAPI.Framework.Content // merge pixels for (int i = 0; i < pixelCount; i++) { - // should probably benchmark this... - ref Color above = ref sourceData[i]; - ref Color below = ref mergedData[i]; + // ref locals here? Not sure. + Color above = sourceData[i]; + Color below = mergedData[i]; // shortcut transparency if (above.A < MinOpacity) diff --git a/src/SMAPI/Framework/Content/AssetEditOperation.cs b/src/SMAPI/Framework/Content/AssetEditOperation.cs index 893f59bd..11b8811b 100644 --- a/src/SMAPI/Framework/Content/AssetEditOperation.cs +++ b/src/SMAPI/Framework/Content/AssetEditOperation.cs @@ -8,5 +8,5 @@ namespace StardewModdingAPI.Framework.Content /// If there are multiple edits that apply to the same asset, the priority with which this one should be applied. /// The content pack on whose behalf the edit is being applied, if any. /// Apply the edit to an asset. - internal readonly record struct AssetEditOperation(IModMetadata Mod, AssetEditPriority Priority, IModMetadata? OnBehalfOf, Action ApplyEdit); + internal record AssetEditOperation(IModMetadata Mod, AssetEditPriority Priority, IModMetadata? OnBehalfOf, Action ApplyEdit); } diff --git a/src/SMAPI/Framework/Content/AssetLoadOperation.cs b/src/SMAPI/Framework/Content/AssetLoadOperation.cs index 58886849..7af07dfd 100644 --- a/src/SMAPI/Framework/Content/AssetLoadOperation.cs +++ b/src/SMAPI/Framework/Content/AssetLoadOperation.cs @@ -8,5 +8,5 @@ namespace StardewModdingAPI.Framework.Content /// If there are multiple loads that apply to the same asset, the priority with which this one should be applied. /// The content pack on whose behalf the asset is being loaded, if any. /// Load the initial value for an asset. - internal readonly record struct AssetLoadOperation(IModMetadata Mod, IModMetadata? OnBehalfOf, AssetLoadPriority Priority, Func GetData); + internal record AssetLoadOperation(IModMetadata Mod, IModMetadata? OnBehalfOf, AssetLoadPriority Priority, Func GetData); } diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs index a8c70356..df7bdc59 100644 --- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs @@ -172,7 +172,7 @@ namespace StardewModdingAPI.Framework.ContentManagers where T : notnull { // find matching loader - AssetLoadOperation loader = default; + AssetLoadOperation? loader = null; if (loadOperations?.Count > 0) { if (!this.AssertMaxOneRequiredLoader(info, loadOperations, out string? error)) @@ -183,7 +183,7 @@ namespace StardewModdingAPI.Framework.ContentManagers loader = loadOperations.OrderByDescending(p => p.Priority).FirstOrDefault(); } - if (loader.Mod == null) // aka, this is default. + if (loader == null) return null; // fetch asset from loader