Пример #1
0
        public void Edit <T> (IAssetData asset)
        {
            IAssetDataForImage editor = asset.AsImage();

            editor.ExtendImage(16, 64);
            editor.PatchImage(icon, targetArea: new Rectangle(0, 48, 16, 16));
        }
Пример #2
0
        /// <summary>Apply the patch to an asset.</summary>
        /// <typeparam name="T">The asset type.</typeparam>
        /// <param name="asset">The asset to edit.</param>
        public void Apply <T>(IAssetData asset)
        {
            // validate
            if (typeof(T) != typeof(Texture2D))
            {
                this.Monitor.Log($"Can't apply edit-image patch by {this.ContentPack.Manifest.Name} to {this.AssetName}: this file isn't an image file (found {typeof(T)}).", LogLevel.Warn);
                return;
            }

            // fetch data
            Texture2D          source = this.AssetLoader.Load <Texture2D>(this.ContentPack, this.FromLocalAsset);
            IAssetDataForImage editor = asset.AsImage();

            // extend tilesheet if needed
            Rectangle affectedArea = this.GetTargetArea(source, this.FromArea, this.ToArea);

            if (affectedArea.Bottom > editor.Data.Height)
            {
                Texture2D original = editor.Data;
                Texture2D texture  = new Texture2D(Game1.graphics.GraphicsDevice, original.Width, affectedArea.Bottom);
                editor.ReplaceWith(texture);
                editor.PatchImage(original);
            }

            // apply source image
            editor.PatchImage(source, this.FromArea, this.ToArea);
        }
Пример #3
0
        /// <summary>
        /// Patches SpaceCore extended tilesheets.
        /// </summary>
        /// <param name="asset"> The asset to change.</param>
        /// <param name="sourceTexture"> The source texture.</param>
        /// <param name="sourceRect"> Source Rectangle of source texture.</param>
        /// <param name="targetRect"> Source Rectangle of target texture.</param>
        public void SpaceCorePatchExtendedTileSheet(IAssetDataForImage asset, Texture2D sourceTexture, Rectangle sourceRect, Rectangle targetRect)
        {
            Assembly   spaceCoreAssembly      = GetSpaceCoreAssembly();
            MethodInfo patchExtendedTileSheet = spaceCoreAssembly.GetType("SpaceCore.TileSheetExtensions").GetMethod("PatchExtendedTileSheet");

            patchExtendedTileSheet.Invoke(null, new object[] { asset, sourceTexture, sourceRect, targetRect, PatchMode.Replace });
        }
Пример #4
0
        /// <summary>Implements <see cref="IAssetEditor.Edit"/>.</summary>
        public void Edit <T>(IAssetData asset)
        {
            if (asset.AssetNameEquals("Characters/Haley") || asset.AssetNameEquals("Portraits/Haley"))
            {
                this.Monitor.Log($"Edit asset {asset.AssetName}");

                IAssetDataForImage baseImage = asset.AsImage();
                // Support for Cold Wether Haley.
                Texture2D overlay = hasColdWeatherHaley_ && Game1.IsWinter
                    ? this.Helper.Content.Load <Texture2D>($"assets/{asset.AssetName}_winter_overlay_hair_gray.png")
                    : this.Helper.Content.Load <Texture2D>($"assets/{asset.AssetName}_overlay_hair_gray.png");

                // Workaround for the missing sleeping sprite of Cold Weather Haley.
                if (hasColdWeatherHaley_ && Game1.IsWinter && asset.AssetNameEquals("Characters/Haley"))
                {
                    Texture2D sleepingHaley = this.Helper.Content.Load <Texture2D>($"assets/{asset.AssetName}_sleeping.png");
                    baseImage.PatchImage(sleepingHaley, patchMode: PatchMode.Overlay);
                }

                baseImage.PatchImage(ColorBlend(overlay, actualHairColor_), patchMode: PatchMode.Overlay);
            }
            else
            {
                throw new ArgumentException($"Invalid asset {asset.AssetName}");
            }
        }
Пример #5
0
        private void ExpandSpriteSheet(IAssetDataForImage assetImage)
        {
            _monitor.VerboseLog("Expanding sprite sheet.");
            var spriteSheet = assetImage.Data;

            _monitor.VerboseLog($"Width: {spriteSheet.Width}, Height: {spriteSheet.Height}");
            if (spriteSheet.Height >= NewHeight)
            {
                return;
            }
            var originalSize = spriteSheet.Width * spriteSheet.Height;
            var data         = new Color[originalSize];

            spriteSheet.GetData(data);
            var originalRect        = new Rectangle(0, 0, spriteSheet.Width, spriteSheet.Height);
            var expandedSpriteSheet = new Texture2D(Game1.graphics.GraphicsDevice, spriteSheet.Width, NewHeight);

            _monitor.VerboseLog($"New width: {expandedSpriteSheet.Width}, New height: {expandedSpriteSheet.Height}");
            expandedSpriteSheet.SetData(0, originalRect, data, 0, originalSize);
            try
            {
                assetImage.ReplaceWith(expandedSpriteSheet);
            }
            catch (Exception ex)
            {
                _monitor.Log("Error while expanding bigCraftableSpriteSheet: " + ex.Message);
            }
        }
Пример #6
0
        private static void UpdateCDForm(IAssetData asset)
        {
            IAssetDataForImage cdForm = asset.AsImage();

            Dictionary <string, string> bundlePrices = GetCurrentBundlePrices();

            foreach (KeyValuePair <string, string> pair in bundlePrices)
            {
                // get number of digits in value
                int numDigits = pair.Value.Length;

                Rectangle sourceRect, destRect;
                Vector2   destStartPos = GetDestStartPos(pair.Key);                 // position on form to start overwriting from
                int       digit, currentPos;

                // need to erase existing numbers
                if (numDigits < 5)
                {
                    // start from 5th position
                    currentPos = 5;
                    // get dots from cdFont.png
                    sourceRect = new Rectangle(70, 0, 35, 11);
                    // get ten-thousands position of destination - slightly different positions on left and right side of form
                    int offset = (pair.Key == "minecarts" || pair.Key == "greenhouse") ? 34 : 33;
                    // get position to overwrite using offset
                    destRect = new Rectangle((int)destStartPos.X - offset, (int)destStartPos.Y, 35, 11);
                    // overwrite with dots
                    cdForm.PatchImage(cdFont, sourceRect, destRect);
                }

                // start at last index in pair.Value; decrement until at first index
                for (int k = pair.Value.Length - 1; k >= 0; k--)
                {
                    // if number is negative, need to set position of '-' manually on tileset
                    if (pair.Value[k] == '-')
                    {
                        digit = 15;
                    }
                    // otherwise convert to int from 0-9 to find position on tileset
                    else
                    {
                        // isolate current digit, convert to int
                        digit = int.Parse(pair.Value[k].ToString());
                    }

                    // get current digit position in number
                    currentPos = numDigits - (k + 1);

                    // create source rectangle by adjusting starting x position by tileset position determined earlier
                    sourceRect = new Rectangle(7 * digit, 0, 7, 11);

                    // get destination rectangle by adjusting start position by current digit position
                    destRect = new Rectangle((int)destStartPos.X - (7 * currentPos), (int)destStartPos.Y, 7, 11);

                    // overwrite current position with digit
                    cdForm.PatchImage(cdFont, sourceRect, destRect);
                }
            }
        }
Пример #7
0
        public void Edit <_T> (IAssetData asset)
        {
            IAssetDataForImage editor = asset.AsImage();

            editor.PatchImage(cursor, targetArea:
                              Game1.getSourceRectForStandardTileSheet(editor.Data,
                                                                      TilePosition, 16, 16));
        }
        public void Edit <T>(IAssetData asset)
        {
            IAssetDataForImage imageAsset = asset.AsImage();

            imageAsset.PatchImage(this.cursor, targetArea:
                                  Game1.getSourceRectForStandardTileSheet(
                                      imageAsset.Data, TILE_POSITION, 16, 16));
        }
Пример #9
0
        /// <summary>Implements <see cref="IAssetEditor.Edit"/>.</summary>
        public void Edit <T>(IAssetData asset)
        {
            if (asset.AssetNameEquals("Characters/Haley") || asset.AssetNameEquals("Portraits/Haley"))
            {
                this.Monitor.Log($"Edit asset {asset.AssetName}");

                IAssetDataForImage baseImage = asset.AsImage();
                Texture2D          overlay;
                // Support for Cold Weather Haley.
                if (hasColdWeatherHaley_ && Game1.IsWinter)
                {
                    overlay = this.Helper.Content.Load <Texture2D>($"assets/{asset.AssetName}_winter_overlay_hair_gray.png");
                    // Workaround for the missing sleeping sprite of Cold Weather Haley.
                    if (asset.AssetNameEquals("Characters/Haley"))
                    {
                        Texture2D sleepingHaley = this.Helper.Content.Load <Texture2D>($"assets/{asset.AssetName}_sleeping.png");
                        baseImage.PatchImage(sleepingHaley, patchMode: PatchMode.Overlay);
                    }
                }
                // Support for RandomFlowerQueen.
                else if (hasRandomFlowerQueen_ && asset.AssetNameEquals("Characters/Haley"))
                {
                    // We must replace the flowerqueen part of the base image since it contains unwanted pixels.
                    Texture2D haleyNoFlowercrown = this.Helper.Content.Load <Texture2D>($"assets/{asset.AssetName}_no_flowercrown.png");
                    baseImage.PatchImage(haleyNoFlowercrown, targetArea: new Rectangle(0, 320, 64, 64), patchMode: PatchMode.Replace);

                    overlay = this.Helper.Content.Load <Texture2D>($"assets/{asset.AssetName}_no_flowercrown_overlay_hair_gray.png");
                }
                else
                {
                    overlay = this.Helper.Content.Load <Texture2D>($"assets/{asset.AssetName}_overlay_hair_gray.png");
                }

                baseImage.PatchImage(ColorBlend(overlay, actualHairColor_), patchMode: PatchMode.Overlay);
            }
            else if (asset.AssetNameEquals("Characters/Haley_Beach") || asset.AssetNameEquals("Portraits/Haley_Beach"))
            {
                this.Monitor.Log($"Edit asset {asset.AssetName}");

                IAssetDataForImage baseImage = asset.AsImage();
                Texture2D          overlay   = this.Helper.Content.Load <Texture2D>($"assets/{asset.AssetName}_overlay_hair_gray.png");

                baseImage.PatchImage(ColorBlend(overlay, actualHairColor_), patchMode: PatchMode.Overlay);
            }
            else if (asset.AssetNameEquals("LooseSprites/cowPhotos") || asset.AssetNameEquals("LooseSprites/cowPhotosWinter"))
            {
                this.Monitor.Log($"Edit asset {asset.AssetName}");

                IAssetDataForImage baseImage = asset.AsImage();
                Texture2D          overlay   = this.Helper.Content.Load <Texture2D>("assets/Characters/Haley_cowPhotos_overlay_hair_gray.png");

                baseImage.PatchImage(ColorBlend(overlay, actualHairColor_), patchMode: PatchMode.Overlay);
            }
            else
            {
                throw new ArgumentException($"Invalid asset {asset.AssetName}");
            }
        }
Пример #10
0
        public void Edit <T>(IAssetData data)
        {
            IAssetDataForImage img = data.AsImage();

            foreach (TextureInjectorInfo entry in TextureInjector.Map[data.AssetName])
            {
                img.PatchImage(entry.Texture, entry.Source, entry.Destination, PatchMode.Replace);
            }
        }
Пример #11
0
        public void SpaceCorePatchExtendedTileSheet(IAssetDataForImage asset, Texture2D sourceTexture, Rectangle sourceRect, Rectangle targetRect)
        {
            var modData                = Helper.ModRegistry.Get("spacechase0.SpaceCore");
            var spaceCoreInstance      = modData.GetType().GetProperty("Mod", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).GetValue(modData);
            var spaceCoreAssembly      = spaceCoreInstance.GetType().Assembly;
            var patchExtendedTileSheet = spaceCoreAssembly.GetType("SpaceCore.TileSheetExtensions").GetMethod("PatchExtendedTileSheet");

            patchExtendedTileSheet.Invoke(null, new object[] { asset, sourceTexture, sourceRect, targetRect, PatchMode.Replace });
        }
Пример #12
0
        /// <summary>Apply the patch to a loaded asset.</summary>
        /// <typeparam name="T">The asset type.</typeparam>
        /// <param name="asset">The asset to edit.</param>
        public override void Edit <T>(IAssetData asset)
        {
            // validate
            if (typeof(T) != typeof(Texture2D))
            {
                this.Monitor.Log($"Can't apply image patch \"{this.LogName}\" to {this.TargetAsset}: this file isn't an image file (found {typeof(T)}).", LogLevel.Warn);
                return;
            }
            if (!this.FromAssetExists())
            {
                this.Monitor.Log($"Can't apply image patch \"{this.LogName}\" to {this.TargetAsset}: the {nameof(PatchConfig.FromFile)} file '{this.FromAsset}' doesn't exist.", LogLevel.Warn);
                return;
            }

            // fetch data
            Texture2D          source     = this.ContentPack.Load <Texture2D>(this.FromAsset);
            Rectangle          sourceArea = this.FromArea ?? new Rectangle(0, 0, source.Width, source.Height);
            Rectangle          targetArea = this.ToArea ?? new Rectangle(0, 0, sourceArea.Width, sourceArea.Height);
            IAssetDataForImage editor     = asset.AsImage();

            // validate error conditions
            if (sourceArea.X < 0 || sourceArea.Y < 0 || sourceArea.Width < 0 || sourceArea.Height < 0)
            {
                this.Monitor.Log($"Can't apply image patch \"{this.LogName}\": source area (X:{sourceArea.X}, Y:{sourceArea.Y}, Width:{sourceArea.Width}, Height:{sourceArea.Height}) has negative values, which isn't valid.", LogLevel.Error);
                return;
            }
            if (targetArea.X < 0 || targetArea.Y < 0 || targetArea.Width < 0 || targetArea.Height < 0)
            {
                this.Monitor.Log($"Can't apply image patch \"{this.LogName}\": target area (X:{targetArea.X}, Y:{targetArea.Y}, Width:{targetArea.Width}, Height:{targetArea.Height}) has negative values, which isn't valid.", LogLevel.Error);
                return;
            }
            if (targetArea.Right > editor.Data.Width)
            {
                this.Monitor.Log($"Can't apply image patch \"{this.LogName}\": target area (X:{targetArea.X}, Y:{targetArea.Y}, Width:{targetArea.Width}, Height:{targetArea.Height}) extends past the right edge of the image (Width:{editor.Data.Width}), which isn't allowed. Patches can only extend the tilesheet downwards.", LogLevel.Error);
                return;
            }
            if (sourceArea.Width != targetArea.Width || sourceArea.Height != targetArea.Height)
            {
                string sourceAreaLabel = this.FromArea.HasValue ? $"{nameof(this.FromArea)}" : "source image";
                string targetAreaLabel = this.ToArea.HasValue ? $"{nameof(this.ToArea)}" : "target image";
                this.Monitor.Log($"Can't apply image patch \"{this.LogName}\": {sourceAreaLabel} size (Width:{sourceArea.Width}, Height:{sourceArea.Height}) doesn't match {targetAreaLabel} size (Width:{targetArea.Width}, Height:{targetArea.Height}).", LogLevel.Error);
                return;
            }

            // extend tilesheet if needed
            if (targetArea.Bottom > editor.Data.Height)
            {
                Texture2D original = editor.Data;
                Texture2D texture  = new Texture2D(Game1.graphics.GraphicsDevice, original.Width, targetArea.Bottom);
                editor.ReplaceWith(texture);
                editor.PatchImage(original);
            }

            // apply source image
            editor.PatchImage(source, sourceArea, this.ToArea, this.PatchMode);
        }
Пример #13
0
        public static bool PatchImage(IAssetDataForImage __instance, ref Texture2D source, ref Rectangle?sourceArea, Rectangle?targetArea, PatchMode patchMode)
        {
            var a  = new Rectangle(0, 0, __instance.Data.Width, __instance.Data.Height);
            var s  = new Rectangle(0, 0, source.Width, source.Height);
            var sr = !sourceArea.HasValue ? s : sourceArea.Value;
            var tr = !targetArea.HasValue ? sr : targetArea.Value;

            if (source is ScaledTexture2D scaled)
            {
                if (a == tr && patchMode == PatchMode.Replace)
                {
                    __instance.ReplaceWith(source);
                    return(true);
                }

                if (patchMode == PatchMode.Overlay)
                {
                    scaled.AsOverlay = true;
                }

                if (scaled.AsOverlay)
                {
                    Color[] data = new Color[(int)(tr.Width) * (int)(tr.Height)];
                    __instance.Data.getArea(tr).GetData(data);
                    scaled.SetData <Color>(data);
                }

                if (__instance.Data is MappedTexture2D map)
                {
                    map.Set(tr, source);
                }
                else
                {
                    __instance.ReplaceWith(new MappedTexture2D(__instance.Data, new Dictionary <Rectangle?, Texture2D>()
                    {
                        { tr, source }
                    }));
                }
            }
            else if (__instance.Data is MappedTexture2D map)
            {
                map.Set(tr, (sr.Width != source.Width || sr.Height != source.Height) ? source.getArea(sr) : source);
                return(false);
            }
            else if (__instance.Data is ScaledTexture2D sc)
            {
                __instance.ReplaceWith(new MappedTexture2D(__instance.Data, new Dictionary <Rectangle?, Texture2D>()
                {
                    { tr, (sr.Width != source.Width || sr.Height != source.Height) ? source.getArea(sr) : source }
                }));
                return(false);
            }

            return(true);
        }
Пример #14
0
        private void PatchSprite(IAssetDataForImage assetImage, CustomChest customChest)
        {
            var sprite          = _modHelper.Content.Load <Texture2D>(customChest.Config.SpritePath);
            var destinationRect = Game1.getSourceRectForStandardTileSheet(Game1.bigCraftableSpriteSheet, customChest.ParentSheetIndex, 16, 32);
            var sourceRect      = new Rectangle(0, 0, 16, 32);

            _monitor.VerboseLog($"Destination rect: ({destinationRect.X}, {destinationRect.Y}) - ({destinationRect.Width}, {destinationRect.Height})");
            try
            {
                assetImage.PatchImage(sprite, targetArea: destinationRect, sourceArea: sourceRect);
            }
            catch (Exception ex)
            {
                _monitor.Log("Error while patching bigCraftableSpriteSheet: " + ex.Message);
            }
        }
Пример #15
0
        public void Edit <T>(IAssetData asset)
        {
            IAssetDataForImage image = asset.AsImage();
            string             name  = Normalize(asset.AssetName) + ".4x";

            if (!ScaledAssets.ContainsKey(name))
            {
                ScaledAssets[name] = new Texture2DWrapper(image.Data, 4, name);
            }
            Texture2DWrapper wrapper = ScaledAssets[name];

            if (wrapper.Locale != asset.Locale)
            {
                Monitor.Log($"Upscaling {asset.AssetName} (Locale: {asset.Locale})");
                wrapper.Wrapped = Texture2DWrapper.ScaleUp(image.Data, wrapper.Scale);
                wrapper.Locale  = asset.Locale;
            }
            image.ReplaceWith(wrapper);
            Helper.Content.Load <Texture2D>(wrapper.Path, ContentSource.GameContent);
        }
 public static bool PatchImage(IAssetDataForImage __instance, Texture2D source, Rectangle?sourceArea, Rectangle?targetArea, PatchMode patchMode)
 {
     if (__instance.Data is Texture2DWrapper wrapper)
     {
         if (sourceArea.HasValue)
         {
             source = Texture2DWrapper.Crop(source, sourceArea.Value);
         }
         source = Texture2DWrapper.ScaleUp(source, wrapper.Scale);
         if (targetArea.HasValue)
         {
             targetArea = Texture2DWrapper.MultiplyRect(targetArea.Value, wrapper.Scale);
         }
         PropertyInfo Data = __instance.GetType().GetProperty("Data");
         Data.SetValue(__instance, wrapper.Wrapped);
         __instance.PatchImage(source, null, targetArea, patchMode);
         Data.SetValue(__instance, wrapper);
         return(false);
     }
     return(true);
 }
        public static void PatchExtendedTileSheet(this IAssetDataForImage asset, Texture2D source, Rectangle?sourceArea = null, Rectangle?targetArea = null, PatchMode patchMode = PatchMode.Replace)
        {
            string assetName = asset.AssetName.Replace('/', '\\');

            if (!extendedTextureAssets.ContainsKey(assetName) || !targetArea.HasValue)
            {
                asset.PatchImage(source, sourceArea, targetArea, patchMode);
                return;
            }
            extendedTextures.Remove(extendedTextureAssets[assetName].BaseTileSheet);
            extendedTextureAssets[assetName].BaseTileSheet = asset.Data;
            extendedTextures.Add(extendedTextureAssets[assetName].BaseTileSheet, extendedTextureAssets[assetName]);

            var adjustedTarget = GetAdjustedTileSheetTarget(asset.Data, targetArea.Value);

            //Log.trace("Tilesheet target:" + adjustedTarget.TileSheet + " " + adjustedTarget.Y);
            if (adjustedTarget.TileSheet == 0)
            {
                asset.PatchImage(source, sourceArea, targetArea, patchMode);
                return;
            }

            // Cheaty hack so I don't have to reimplement patch
            var oldData  = asset.Data;
            var dataProp = asset.GetType().GetProperty("Data");

            try
            {
                dataProp.SetValue(asset, GetTileSheet(oldData, adjustedTarget.TileSheet));

                Rectangle r = targetArea.Value;
                r.Y = adjustedTarget.Y;
                //Log.trace($"Ext-patching on {assetName}={extendedTextureAssets[assetName].AssetPath}: {r}/{asset.Data.Width}x{asset.Data.Height}");
                asset.PatchImage(source, sourceArea, r, patchMode);
            }
            finally
            {
                dataProp.SetValue(asset, oldData);
            }
        }
Пример #18
0
        /// <inheritdoc />
        public override void Edit <T>(IAssetData asset)
        {
            // validate
            if (typeof(T) != typeof(Texture2D))
            {
                this.Warn($"this file isn't an image file (found {typeof(T)}).");
                return;
            }
            if (!this.FromAssetExists())
            {
                this.Warn($"the {nameof(PatchConfig.FromFile)} file '{this.FromAsset}' doesn't exist.");
                return;
            }

            // get editor
            IAssetDataForImage editor = asset.AsImage();

            // fetch data
            this.LoadSourceImage(this.FromAsset, out int sourceWidth, out int sourceHeight, out IRawTextureData? rawSource, out Texture2D? fullSource);
            if (!this.TryReadArea(this.FromArea, 0, 0, sourceWidth, sourceHeight, out Rectangle sourceArea, out string?error))
            {
                this.Warn($"the source area is invalid: {error}.");
                return;
            }
            if (!this.TryReadArea(this.ToArea, 0, 0, sourceArea.Width, sourceArea.Height, out Rectangle targetArea, out error))
            {
                this.Warn($"the target area is invalid: {error}.");
                return;
            }

            // validate error conditions
            if (sourceArea.X < 0 || sourceArea.Y < 0 || sourceArea.Width < 0 || sourceArea.Height < 0)
            {
                this.Warn($"source area (X:{sourceArea.X}, Y:{sourceArea.Y}, Width:{sourceArea.Width}, Height:{sourceArea.Height}) has negative values, which isn't valid.", LogLevel.Error);
                return;
            }
            if (targetArea.X < 0 || targetArea.Y < 0 || targetArea.Width < 0 || targetArea.Height < 0)
            {
                this.Warn($"target area (X:{targetArea.X}, Y:{targetArea.Y}, Width:{targetArea.Width}, Height:{targetArea.Height}) has negative values, which isn't valid.", LogLevel.Error);
                return;
            }
            if (targetArea.Right > editor.Data.Width)
            {
                this.Warn($"target area (X:{targetArea.X}, Y:{targetArea.Y}, Width:{targetArea.Width}, Height:{targetArea.Height}) extends past the right edge of the image (Width:{editor.Data.Width}), which isn't allowed. Patches can only extend the tilesheet downwards.", LogLevel.Error);
                return;
            }
            if (sourceArea.Width != targetArea.Width || sourceArea.Height != targetArea.Height)
            {
                string sourceAreaLabel = this.FromArea != null ? $"{nameof(this.FromArea)}" : "source image";
                string targetAreaLabel = this.ToArea != null ? $"{nameof(this.ToArea)}" : "target image";
                this.Warn($"{sourceAreaLabel} size (Width:{sourceArea.Width}, Height:{sourceArea.Height}) doesn't match {targetAreaLabel} size (Width:{targetArea.Width}, Height:{targetArea.Height}).", LogLevel.Error);
                return;
            }

            // extend tilesheet if needed
            this.ResizedLastImage = editor.ExtendImage(editor.Data.Width, targetArea.Bottom);

            // apply source image
            if (rawSource is not null)
            {
                editor.PatchImage(rawSource, sourceArea, targetArea, (PatchMode)this.PatchMode);
            }
            else
            {
                editor.PatchImage(fullSource !, sourceArea, targetArea, (PatchMode)this.PatchMode);
            }
        }
Пример #19
0
 public static bool ExtendImage(IAssetDataForImage __instance, int minWidth, int minHeight)
 {
     return(!(__instance.Data is ScaledTexture2D || __instance.Data is MappedTexture2D));
 }
        public void Edit <_T> (IAssetData asset)
        {
            IAssetDataForImage editor = asset.AsImage();

            editor.PatchImage(cursor, targetArea: new Rectangle(112, 0, 16, 16));
        }
Пример #21
0
    public static bool PatchImage(IAssetDataForImage __instance, XTexture2D source, XRectangle?sourceArea, XRectangle?targetArea, PatchMode patchMode)
    {
        if (!Config.SMAPI.ApplyPatchEnabled)
        {
            return(true);
        }

        // get texture
        if (source is null)
        {
            throw new ArgumentNullException(nameof(source), "Can't patch from a null source texture.");
        }

        XTexture2D target = __instance.Data;

        // get areas
        sourceArea ??= new(0, 0, source.Width, source.Height);
        targetArea ??= new(0, 0, Math.Min(sourceArea.Value.Width, target.Width), Math.Min(sourceArea.Value.Height, target.Height));

        // validate
        if (!source.Bounds.Contains(sourceArea.Value))
        {
            throw new ArgumentOutOfRangeException(nameof(sourceArea), "The source area is outside the bounds of the source texture.");
        }
        if (!target.Bounds.Contains(targetArea.Value))
        {
            throw new ArgumentOutOfRangeException(nameof(targetArea), "The target area is outside the bounds of the target texture.");
        }
        if (sourceArea.Value.Size != targetArea.Value.Size)
        {
            throw new InvalidOperationException("The source and target areas must be the same size.");
        }

        if (GL.Texture2DExt.CopyTexture(source, sourceArea.Value, target, targetArea.Value, patchMode))
        {
            return(false);
        }

        // get source data
        int pixelCount = sourceArea.Value.Width * sourceArea.Value.Height;
        var sourceData = GC.AllocateUninitializedArray <XColor>(pixelCount);

        source.GetData(0, sourceArea, sourceData, 0, pixelCount);

        // merge data in overlay mode
        if (patchMode == PatchMode.Overlay)
        {
            // get target data
            var targetData = GC.AllocateUninitializedArray <XColor>(pixelCount);
            target.GetData(0, targetArea, targetData, 0, pixelCount);

            // merge pixels
            for (int i = 0; i < sourceData.Length; i++)
            {
                var above = sourceData[i];
                var below = targetData[i];

                // shortcut transparency
                if (above.A < MinOpacity)
                {
                    sourceData[i] = below;
                    continue;
                }
                if (below.A < MinOpacity)
                {
                    sourceData[i] = above;
                    continue;
                }

                // merge pixels
                // This performs a conventional alpha blend for the pixels, which are already
                // premultiplied by the content pipeline. The formula is derived from
                // https://shawnhargreaves.com/blog/premultiplied-alpha.html.
                float alphaBelow = 1 - (above.A / 255f);
                sourceData[i] = new XColor(
                    (int)(above.R + (below.R * alphaBelow)),               // r
                    (int)(above.G + (below.G * alphaBelow)),               // g
                    (int)(above.B + (below.B * alphaBelow)),               // b
                    Math.Max(above.A, below.A)                             // a
                    );
            }
        }

        // patch target texture
        target.SetData(0, targetArea, sourceData, 0, pixelCount);
        return(false);
    }
        /// <summary>Apply the patch to a loaded asset.</summary>
        /// <typeparam name="T">The asset type.</typeparam>
        /// <param name="asset">The asset to edit.</param>
        public override void Edit <T>(IAssetData asset)
        {
            string errorPrefix = $"Can't apply image patch \"{this.LogName}\" to {this.TargetAsset}";

            // validate
            if (typeof(T) != typeof(Texture2D))
            {
                this.Monitor.Log($"{errorPrefix}: this file isn't an image file (found {typeof(T)}).", LogLevel.Warn);
                return;
            }
            if (!this.FromAssetExists())
            {
                this.Monitor.Log($"{errorPrefix}: the {nameof(PatchConfig.FromFile)} file '{this.FromAsset}' doesn't exist.", LogLevel.Warn);
                return;
            }

            // fetch data
            IAssetDataForImage editor = asset.AsImage();
            Texture2D          source = this.ContentPack.Load <Texture2D>(this.FromAsset);

            if (!this.TryReadArea(this.FromArea, 0, 0, source.Width, source.Height, out Rectangle sourceArea, out string error))
            {
                this.Monitor.Log($"{errorPrefix}: the source area is invalid: {error}.", LogLevel.Warn);
                return;
            }
            if (!this.TryReadArea(this.ToArea, 0, 0, sourceArea.Width, sourceArea.Height, out Rectangle targetArea, out error))
            {
                this.Monitor.Log($"{errorPrefix}: the target area is invalid: {error}.", LogLevel.Warn);
                return;
            }

            // validate error conditions
            if (sourceArea.X < 0 || sourceArea.Y < 0 || sourceArea.Width < 0 || sourceArea.Height < 0)
            {
                this.Monitor.Log($"{errorPrefix}: source area (X:{sourceArea.X}, Y:{sourceArea.Y}, Width:{sourceArea.Width}, Height:{sourceArea.Height}) has negative values, which isn't valid.", LogLevel.Error);
                return;
            }
            if (targetArea.X < 0 || targetArea.Y < 0 || targetArea.Width < 0 || targetArea.Height < 0)
            {
                this.Monitor.Log($"{errorPrefix}: target area (X:{targetArea.X}, Y:{targetArea.Y}, Width:{targetArea.Width}, Height:{targetArea.Height}) has negative values, which isn't valid.", LogLevel.Error);
                return;
            }
            if (targetArea.Right > editor.Data.Width)
            {
                this.Monitor.Log($"{errorPrefix}: target area (X:{targetArea.X}, Y:{targetArea.Y}, Width:{targetArea.Width}, Height:{targetArea.Height}) extends past the right edge of the image (Width:{editor.Data.Width}), which isn't allowed. Patches can only extend the tilesheet downwards.", LogLevel.Error);
                return;
            }
            if (sourceArea.Width != targetArea.Width || sourceArea.Height != targetArea.Height)
            {
                string sourceAreaLabel = this.FromArea != null ? $"{nameof(this.FromArea)}" : "source image";
                string targetAreaLabel = this.ToArea != null ? $"{nameof(this.ToArea)}" : "target image";
                this.Monitor.Log($"{errorPrefix}: {sourceAreaLabel} size (Width:{sourceArea.Width}, Height:{sourceArea.Height}) doesn't match {targetAreaLabel} size (Width:{targetArea.Width}, Height:{targetArea.Height}).", LogLevel.Error);
                return;
            }

            // extend tilesheet if needed
            this.ResizedLastImage = editor.ExtendImage(editor.Data.Width, targetArea.Bottom);

            // apply source image
            editor.PatchImage(source, sourceArea, targetArea, this.PatchMode);
        }
        public void Edit <T>(IAssetData asset)
        {
            VoidshroomSpore.setIndex(); //get an item index for voidshroom spores if one isn't already set.
            CaveCarrotSeed.setIndex();
            CaveCarrot.setIndex();
            CaveCarrot.setCropIndex();
            if (asset.AssetNameEquals("Maps\\springobjects"))
            {
                IAssetDataForImage editor    = asset.AsImage();
                Texture2D          data      = editor.Data;
                Texture2D          texture2D = new Texture2D(Game1.graphics.GraphicsDevice, data.Width, Math.Max(data.Height, 4096));
                editor.ReplaceWith(texture2D);
                editor.PatchImage(data, new Rectangle?(), new Rectangle?(), PatchMode.Replace);
                try
                {
                    editor.PatchImage(TextureSet.voidShroomSpore, new Rectangle?(), new Rectangle?(this.objectRect(VoidshroomSpore.getIndex())), PatchMode.Replace);
                    editor.PatchImage(TextureSet.caveCarrotSeed, new Rectangle?(), new Rectangle?(this.objectRect(CaveCarrotSeed.getIndex())), PatchMode.Replace);
                }
                catch (Exception)
                {
                }
            }
            else if (asset.AssetNameEquals("Data\\ObjectInformation"))
            {
                IAssetDataForDictionary <int, string> editor = asset.AsDictionary <int, string>();

                IDictionary <int, string> data = editor.Data;
                if (!data.ContainsKey(VoidshroomSpore.getIndex()))
                {
                    int    voidShroomSporeIndex = VoidshroomSpore.getIndex();
                    String voidShroomSpore      = VoidshroomSpore.getObjectData();
                    this.log("Add voidshroom spore object data: " + voidShroomSporeIndex + ": " + voidShroomSpore);
                    data.Add(voidShroomSporeIndex, voidShroomSpore);
                }

                if (!data.ContainsKey(CaveCarrotSeed.getIndex()))
                {
                    int    caveCarrotSeedIndex = CaveCarrotSeed.getIndex();
                    String caveCarrotObject    = CaveCarrotSeed.getObjectData();
                    this.log("Add cave carrot seed object data: " + caveCarrotSeedIndex + ": " + caveCarrotObject);
                    data.Add(caveCarrotSeedIndex, caveCarrotObject);
                }

                if (!data.ContainsKey(CaveCarrotFlower.getIndex()))
                {
                    int    caveCarrotFlowerIndex  = CaveCarrotFlower.getIndex();
                    String caveCarrotFlowerObject = CaveCarrotFlower.getObjectData();
                    this.log("Add cave carrot flower 'seed' data: " + caveCarrotFlowerIndex + ": " + caveCarrotFlowerObject);
                    data.Add(caveCarrotFlowerIndex, caveCarrotFlowerObject);
                }
            }
            else if (asset.AssetNameEquals("Data\\Crops"))
            {
                IAssetDataForDictionary <int, string> editor = asset.AsDictionary <int, string>();
                IDictionary <int, string>             data   = editor.Data;

                int seedIndex = CaveCarrot.getIndex();
                this.log("seedIndex is: " + seedIndex);
                if (!data.ContainsKey(seedIndex))
                {
                    String cropData = CaveCarrot.getCropData();
                    this.monitor.Log("Loading crop data: " + cropData);
                    data.Add(CaveCarrot.getIndex(), cropData);
                }

                int caveCarrotFlowerIndex = CaveCarrotFlower.getIndex();
                this.log("seedIndex is: " + caveCarrotFlowerIndex);
                if (!data.ContainsKey(caveCarrotFlowerIndex))
                {
                    String cropData = CaveCarrotFlower.getCropData();
                    this.monitor.Log("Loading crop data: " + cropData);
                    data.Add(caveCarrotFlowerIndex, cropData);
                }
            }
            else if (asset.AssetNameEquals("TileSheets\\crops"))
            {
                IAssetDataForImage editor    = asset.AsImage();
                Texture2D          data      = editor.Data;
                Texture2D          texture2D = new Texture2D(Game1.graphics.GraphicsDevice, data.Width, Math.Max(data.Height, 4096));
                editor.ReplaceWith(texture2D);
                editor.PatchImage(data, new Rectangle?(), new Rectangle?(), PatchMode.Replace);
                try
                {
                    int index = CaveCarrot.getCropIndex();
                    this.monitor.Log("Loading cave carrot crop texture.  Crop index: " + index);
                    editor.PatchImage(TextureSet.caveCarrotCrop, new Rectangle?(), new Rectangle?(this.cropRect(index)), PatchMode.Replace);

                    index = CaveCarrotFlower.getCropIndex();
                    this.monitor.Log("Loading cave carrot flower crop texture.  Crop index: " + index);
                    editor.PatchImage(TextureSet.caveCarrotFlowerCrop, new Rectangle?(), new Rectangle?(this.cropRect(index)), PatchMode.Replace);
                }
                catch (Exception)
                {
                }
            }
        }
Пример #24
0
        public void Edit <T>(IAssetData asset)
        {
            if (asset.AssetNameEquals(System.IO.Path.Combine("Data", "ObjectInformation")))
            {
                IDictionary <int, string> data = asset.AsDictionary <int, string>().Data;
                if (Constants.CurrentSavePath == null)
                {
                    List <int> dataKeys = new List <int>(data.Keys);
                    dataKeys.Sort();
                    largestItemID = dataKeys[dataKeys.Count - 1];
                }
                else
                {
                    string smallEggData = "Egg/{{sell price}}/10/Basic -5/Egg/A{{species}} egg.";
                    string largeEggData = "Large Egg/{{sell price}}/15/Basic -5/Large Egg/It's an uncommonly large {{species}} egg!";
                    string eggData;
                    foreach (int id in modData.customEggsAndHatchedAnimals.Keys)
                    {
                        string speciesName = modData.customEggsAndHatchedAnimals[id][modDataBreedIndex].ToLower();
                        if (IsDeluxeEgg(id))
                        {
                            eggData = largeEggData;
                            if (modData.customEggsAndHatchedAnimals[id][modDataEggAspectIndex] != "true")
                            {
                                eggData = eggData.Replace("large", modData.customEggsAndHatchedAnimals[id][modDataEggAspectIndex]);
                            }
                            int multiplier = DeluxeProductMultiplier(id);
                            if (multiplier > 1)
                            {
                                eggData = eggData.Replace("Large Egg", "Egg x" + multiplier);
                            }
                        }
                        else
                        {
                            eggData = smallEggData;
                            if ("aeiouAEIOU".IndexOf(speciesName[0]) >= 0)
                            {
                                speciesName = "n " + speciesName;
                            }
                            else
                            {
                                speciesName = " " + speciesName;
                            }
                        }
                        eggData = eggData.Replace("{{species}}", speciesName).Replace("{{sell price}}", modData.customEggsAndHatchedAnimals[id][modDataPriceIndex]);

                        if (!data.ContainsKey(id))
                        {
                            data.Add(id, eggData);
                        }
                    }
                }
            }
            else if (chickenContentHandled && asset.AssetNameEquals(System.IO.Path.Combine("Data", "FarmAnimals")))
            {
                EditFarmAnimalsData(asset);
            }
            else if (eggContentHandled && asset.AssetNameEquals(System.IO.Path.Combine("Maps", "springobjects")))
            {
                foreach (int itemID in customEggTextures.Keys)
                {
                    Vector2 spriteSheetCoords = GetSpritesheetCoordsFromItemID(itemID);

                    IAssetDataForImage editor     = asset.AsImage();
                    Texture2D          eggTexture = smapiHelper.Content.Load <Texture2D>(customEggTextures[itemID], ContentSource.GameContent);
                    Rectangle          fromArea   = new Rectangle(0, 0, 16, 16);
                    Rectangle          targetArea = new Rectangle((int)spriteSheetCoords.X, (int)spriteSheetCoords.Y, 16, 16);

                    // extend tilesheet if needed
                    if (targetArea.Bottom > editor.Data.Height)
                    {
                        Texture2D original = editor.Data;
                        Texture2D texture  = new Texture2D(Game1.graphics.GraphicsDevice, original.Width, targetArea.Bottom);
                        editor.ReplaceWith(texture);
                        editor.PatchImage(original);
                    }

                    editor.PatchImage(eggTexture, fromArea, targetArea, PatchMode.Replace);
                }
            }
        }