From d29c01b8155a6fe2607066da6f0a5cfb45b28d3c Mon Sep 17 00:00:00 2001
From: atravita-mods <94934860+atravita-mods@users.noreply.github.com>
Date: Thu, 18 Aug 2022 20:51:45 -0400
Subject: Partially revert "Favor record structs when there are four or fewer
 elements."

This reverts commit f5d49515c4eddfb415903a89d70654cf9b6de299.
---
 src/SMAPI/Framework/Content/AssetDataForImage.cs   | 36 ++++++++++------------
 src/SMAPI/Framework/Content/AssetEditOperation.cs  |  2 +-
 src/SMAPI/Framework/Content/AssetLoadOperation.cs  |  2 +-
 .../ContentManagers/GameContentManager.cs          |  4 +--
 4 files changed, 21 insertions(+), 23 deletions(-)

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<Color>.Shared.Rent(pixelCount);
+                    sourceData = ArrayPool<Color>.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;
+                        // 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<Color>.Shared.Return(trimmedSourceData);
+                    ArrayPool<Color>.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
     /// <param name="Priority">If there are multiple edits that apply to the same asset, the priority with which this one should be applied.</param>
     /// <param name="OnBehalfOf">The content pack on whose behalf the edit is being applied, if any.</param>
     /// <param name="ApplyEdit">Apply the edit to an asset.</param>
-    internal readonly record struct AssetEditOperation(IModMetadata Mod, AssetEditPriority Priority, IModMetadata? OnBehalfOf, Action<IAssetData> ApplyEdit);
+    internal record AssetEditOperation(IModMetadata Mod, AssetEditPriority Priority, IModMetadata? OnBehalfOf, Action<IAssetData> 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
     /// <param name="Priority">If there are multiple loads that apply to the same asset, the priority with which this one should be applied.</param>
     /// <param name="OnBehalfOf">The content pack on whose behalf the asset is being loaded, if any.</param>
     /// <param name="GetData">Load the initial value for an asset.</param>
-    internal readonly record struct AssetLoadOperation(IModMetadata Mod, IModMetadata? OnBehalfOf, AssetLoadPriority Priority, Func<IAssetInfo, object> GetData);
+    internal record AssetLoadOperation(IModMetadata Mod, IModMetadata? OnBehalfOf, AssetLoadPriority Priority, Func<IAssetInfo, object> 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
-- 
cgit