summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/StardewModdingAPI/Framework/ContentEventHelper.cs51
-rw-r--r--src/StardewModdingAPI/IContentEventHelper.cs12
-rw-r--r--src/StardewModdingAPI/PatchMode.cs12
-rw-r--r--src/StardewModdingAPI/StardewModdingAPI.csproj1
4 files changed, 76 insertions, 0 deletions
diff --git a/src/StardewModdingAPI/Framework/ContentEventHelper.cs b/src/StardewModdingAPI/Framework/ContentEventHelper.cs
index a58efe32..ebd04692 100644
--- a/src/StardewModdingAPI/Framework/ContentEventHelper.cs
+++ b/src/StardewModdingAPI/Framework/ContentEventHelper.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace StardewModdingAPI.Framework
@@ -85,6 +86,56 @@ namespace StardewModdingAPI.Framework
data[key] = value(data[key]);
}
+ /// <summary>Overwrite part of the image.</summary>
+ /// <param name="source">The image to patch into the content.</param>
+ /// <param name="sourceArea">The part of the <paramref name="source"/> to copy (or <c>null</c> to take the whole texture). This must be within the bounds of the <paramref name="source"/> texture.</param>
+ /// <param name="targetArea">The part of the content to patch (or <c>null</c> to patch the whole texture). The original content within this area will be erased. This must be within the bounds of the existing spritesheet.</param>
+ /// <param name="patchMode">Indicates how an image should be patched.</param>
+ /// <exception cref="ArgumentNullException">One of the arguments is null.</exception>
+ /// <exception cref="ArgumentOutOfRangeException">The <paramref name="targetArea"/> is outside the bounds of the spritesheet.</exception>
+ /// <exception cref="InvalidOperationException">The content being read isn't an image.</exception>
+ public void PatchImage(Texture2D source, Rectangle? sourceArea = null, Rectangle? targetArea = null, PatchMode patchMode = PatchMode.Replace)
+ {
+ // get texture
+ Texture2D target = this.GetData<Texture2D>();
+
+ // get areas
+ sourceArea = sourceArea ?? new Rectangle(0, 0, source.Width, source.Height);
+ targetArea = targetArea ?? new Rectangle(0, 0, Math.Min(sourceArea.Value.Width, target.Width), Math.Min(sourceArea.Value.Height, target.Height));
+
+ // validate
+ if (source == null)
+ throw new ArgumentNullException(nameof(source), "Can't patch from a null source texture.");
+ if (sourceArea.Value.X < 0 || sourceArea.Value.Y < 0 || sourceArea.Value.Right > source.Width || sourceArea.Value.Bottom > source.Height)
+ throw new ArgumentOutOfRangeException(nameof(sourceArea), "The source area is outside the bounds of the source texture.");
+ if (targetArea.Value.X < 0 || targetArea.Value.Y < 0 || targetArea.Value.Right > target.Width || targetArea.Value.Bottom > target.Height)
+ throw new ArgumentOutOfRangeException(nameof(targetArea), "The target area is outside the bounds of the target texture.");
+ if (sourceArea.Value.Width != targetArea.Value.Width || sourceArea.Value.Height != targetArea.Value.Height)
+ throw new InvalidOperationException("The source and target areas must be the same size.");
+
+ // get source data
+ int pixelCount = sourceArea.Value.Width * sourceArea.Value.Height;
+ Color[] sourceData = new Color[pixelCount];
+ source.GetData(0, sourceArea, sourceData, 0, pixelCount);
+
+ // merge data in overlay mode
+ if (patchMode == PatchMode.Overlay)
+ {
+ Color[] newData = new Color[targetArea.Value.Width * targetArea.Value.Height];
+ target.GetData(0, targetArea, newData, 0, newData.Length);
+ for (int i = 0; i < sourceData.Length; i++)
+ {
+ Color pixel = sourceData[i];
+ if (pixel.A != 0) // not transparent
+ newData[i] = pixel;
+ }
+ sourceData = newData;
+ }
+
+ // patch target texture
+ target.SetData(0, targetArea, sourceData, 0, pixelCount);
+ }
+
/// <summary>Replace the entire content value with the given value. This is generally not recommended, since it may break compatibility with other mods or different versions of the game.</summary>
/// <param name="value">The new content value.</param>
/// <exception cref="ArgumentNullException">The <paramref name="value"/> is null.</exception>
diff --git a/src/StardewModdingAPI/IContentEventHelper.cs b/src/StardewModdingAPI/IContentEventHelper.cs
index be8290eb..7b8fd3bc 100644
--- a/src/StardewModdingAPI/IContentEventHelper.cs
+++ b/src/StardewModdingAPI/IContentEventHelper.cs
@@ -1,4 +1,6 @@
using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
namespace StardewModdingAPI
{
@@ -46,6 +48,16 @@ namespace StardewModdingAPI
/// <exception cref="InvalidOperationException">The content being read isn't a dictionary.</exception>
void SetDictionaryEntry<TKey, TValue>(TKey key, Func<TValue, TValue> value);
+ /// <summary>Overwrite part of the image.</summary>
+ /// <param name="source">The image to patch into the content.</param>
+ /// <param name="sourceArea">The part of the <paramref name="source"/> to copy (or <c>null</c> to take the whole texture). This must be within the bounds of the <paramref name="source"/> texture.</param>
+ /// <param name="targetArea">The part of the content to patch (or <c>null</c> to patch the whole texture). The original content within this area will be erased. This must be within the bounds of the existing spritesheet.</param>
+ /// <param name="patchMode">Indicates how an image should be patched.</param>
+ /// <exception cref="ArgumentNullException">One of the arguments is null.</exception>
+ /// <exception cref="ArgumentOutOfRangeException">The <paramref name="targetArea"/> is outside the bounds of the spritesheet.</exception>
+ /// <exception cref="InvalidOperationException">The content being read isn't an image.</exception>
+ void PatchImage(Texture2D source, Rectangle? sourceArea = null, Rectangle? targetArea = null, PatchMode patchMode = PatchMode.Replace);
+
/// <summary>Replace the entire content value with the given value. This is generally not recommended, since it may break compatibility with other mods or different versions of the game.</summary>
/// <param name="value">The new content value.</param>
/// <exception cref="ArgumentNullException">The <paramref name="value"/> is null.</exception>
diff --git a/src/StardewModdingAPI/PatchMode.cs b/src/StardewModdingAPI/PatchMode.cs
new file mode 100644
index 00000000..b4286a89
--- /dev/null
+++ b/src/StardewModdingAPI/PatchMode.cs
@@ -0,0 +1,12 @@
+namespace StardewModdingAPI
+{
+ /// <summary>Indicates how an image should be patched.</summary>
+ public enum PatchMode
+ {
+ /// <summary>Erase the original content within the area before drawing the new content.</summary>
+ Replace,
+
+ /// <summary>Draw the new content over the original content, so the original content shows through any transparent pixels.</summary>
+ Overlay
+ }
+}
diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj
index 4d782f56..40f964b9 100644
--- a/src/StardewModdingAPI/StardewModdingAPI.csproj
+++ b/src/StardewModdingAPI/StardewModdingAPI.csproj
@@ -196,6 +196,7 @@
<Compile Include="Framework\Manifest.cs" />
<Compile Include="Mod.cs" />
<Compile Include="Framework\ModHelper.cs" />
+ <Compile Include="PatchMode.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Framework\SGame.cs" />