Skip to content

Commit

Permalink
feat: multiple bundle decorator display (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
gottyduke authored Mar 27, 2024
1 parent 9c21a28 commit f92e3ea
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 34 deletions.
5 changes: 5 additions & 0 deletions Informant/Api/Decoration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,9 @@ public record Decoration(Texture2D Texture)
/// Optionally displays a little number over the texture.
/// </summary>
public int? Counter { get; init; }

/// <summary>
/// Optional extra decorations of the same decorator.
/// </summary>
public Decoration[]? ExtraDecorations { get; init; }
}
18 changes: 18 additions & 0 deletions Informant/Helper/TextureBlitter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Microsoft.Xna.Framework.Graphics;
using Color = Microsoft.Xna.Framework.Color;
using Rectangle = Microsoft.Xna.Framework.Rectangle;

namespace Slothsoft.Informant.Helper;

internal static class TextureBlitter
{
public static Texture2D Blit(this Texture2D source, Rectangle rectangle, GraphicsDevice? device = null)
{
device ??= Game1.graphics.GraphicsDevice;
var texture = new Texture2D(device, rectangle.Width, rectangle.Height);
Color[] data = new Color[rectangle.Width * rectangle.Height];
source.GetData(0, rectangle, data, 0, data.Length);
texture.SetData(data);
return texture;
}
}
72 changes: 41 additions & 31 deletions Informant/Implementation/Decorator/BundleDecorator.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
using Microsoft.Xna.Framework.Graphics;
using Slothsoft.Informant.Api;
using Slothsoft.Informant.Helper;
using StardewValley.Locations;
using StardewValley.Menus;
using Color = Microsoft.Xna.Framework.Color;
using Rectangle = Microsoft.Xna.Framework.Rectangle;


namespace Slothsoft.Informant.Implementation.Decorator;

internal class BundleDecorator : IDecorator<Item>
{
internal record ParsedSimpleBundle
{
public int ParentSheetIndex;
public int Quantity;
public int Quality;
public int Color;
}

public const int DefaultBundleColor = -1;

private static Texture2D? _bundle;
private static Dictionary<int, Texture2D> _bundles = [];
private static int? _lastCachedItemQuantity;
private static int? _lastCachedBundleColor;
private static IEnumerable<ParsedSimpleBundle>? _lastCachedBundles;

private readonly IModHelper _modHelper;

public BundleDecorator(IModHelper modHelper)
{
_modHelper = modHelper;
_bundle ??= Game1.temporaryContent.Load<Texture2D>("LooseSprites\\JunimoNote");
_bundles[-1] = modHelper.ModContent.Load<Texture2D>("assets/bundle.png");
_bundles[DefaultBundleColor] = modHelper.ModContent.Load<Texture2D>("assets/bundle.png");
}

public string Id => "bundles";
Expand All @@ -33,7 +45,6 @@ public bool HasDecoration(Item input)
}

if (_bundles.Any() && input is SObject obj && !obj.bigCraftable.Value) {

int[]? allowedAreas;

if (!Game1.MasterPlayer.mailReceived.Contains("canReadJunimoText")) {
Expand All @@ -49,22 +60,14 @@ public bool HasDecoration(Item input)
.ToArray();
}

var neededItems = GetNeededItems(allowedAreas, InformantMod.Instance?.Config.DecorateLockedBundles ?? false)
.Where(item => item[0] == input.ParentSheetIndex);
if (neededItems.Any()) {
_lastCachedItemQuantity = neededItems.First()[1];
_lastCachedBundleColor = neededItems.First()[2];
} else {
_lastCachedItemQuantity = null;
_lastCachedBundleColor = null;
}

return neededItems.Any();
_lastCachedBundles = GetNeededItems(allowedAreas, InformantMod.Instance?.Config.DecorateLockedBundles ?? false)
.Where(item => input.ParentSheetIndex == item.ParentSheetIndex && input.quality.Value <= item.Quality);
return _lastCachedBundles.Any();
}
return false;
}

internal static IEnumerable<int[]> GetNeededItems(int[]? allowedAreas, bool decorateLockedBundles)
internal static IEnumerable<ParsedSimpleBundle> GetNeededItems(int[]? allowedAreas, bool decorateLockedBundles)
{
// BUNDLE DATA
// ============
Expand Down Expand Up @@ -96,15 +99,22 @@ internal static IEnumerable<int[]> GetNeededItems(int[]? allowedAreas, bool deco
// bundle was not yet unlocked or already completed
continue;
}

_ = int.TryParse(bundleTitleSplit[1], out var bundleIndex);
var bundleDataSplit = bundleData[bundleTitle].Split('/');
var indexStackQuality = bundleDataSplit[2].Split(' ');
for (var index = 0; index < indexStackQuality.Length; index += 3) {
if (!bundlesCompleted[bundleIndex][index / 3]) {
if (int.TryParse(indexStackQuality[index], out var parentSheetIndex)) {
_ = int.TryParse(indexStackQuality[index + 1], out var quantity);
GetOrCacheBundleTexture(int.TryParse(bundleDataSplit[3], out var color) ? color : null);
yield return [parentSheetIndex, quantity, color];
_ = int.TryParse(indexStackQuality[index + 2], out var quality);
_ = int.TryParse(bundleDataSplit[3], out var color);
yield return new ParsedSimpleBundle {
ParentSheetIndex = parentSheetIndex,
Quantity = quantity,
Quality = quality,
Color = color,
};
}
}
}
Expand All @@ -113,24 +123,24 @@ internal static IEnumerable<int[]> GetNeededItems(int[]? allowedAreas, bool deco

internal static Texture2D GetOrCacheBundleTexture(int? color)
{
var colorIndex = color ?? -1;
if (_bundles.ContainsKey(colorIndex)) {
return _bundles[colorIndex];
var colorIndex = color ?? DefaultBundleColor;
if (!_bundles.ContainsKey(colorIndex)) {
var rect = new Rectangle(colorIndex * 256 % 512, 244 + colorIndex * 256 / 512 * 16, 16, 16);
_bundles[colorIndex] = _bundle!.Blit(rect);
}

var rect = new Rectangle(colorIndex * 256 % 512, 244 + colorIndex * 256 / 512 * 16, 16, 16);
var note = new Texture2D(Game1.graphics.GraphicsDevice, 16, 16);
Color[] data = new Color[256];

_bundle!.GetData(0, rect, data, 0, data.Length);
note.SetData(data);
_bundles[colorIndex] = note;

return note;
return _bundles[colorIndex];
}

public Decoration Decorate(Item input)
{
return new Decoration(GetOrCacheBundleTexture(_lastCachedBundleColor)) { Counter = _lastCachedItemQuantity };
var decorations = _lastCachedBundles!
.Skip(1)
.Select(bundle => new Decoration(GetOrCacheBundleTexture(bundle.Color)) { Counter = bundle.Quantity })
.ToArray();
return new Decoration(GetOrCacheBundleTexture(_lastCachedBundles!.First().Color)) {
Counter = _lastCachedBundles!.First().Quantity,
ExtraDecorations = decorations
};
}
}
7 changes: 5 additions & 2 deletions Informant/Implementation/ItemDecoratorManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ private static void DrawToolTip(SpriteBatch b, Item? hoveredItem)
var decorations = DecoratorsList
.Where(g => config.DisplayIds.GetValueOrDefault(g.Id, true))
.Where(d => d.HasDecoration(hoveredItem))
.Select(d => d.Decorate(hoveredItem))
.SelectMany(d => {
var decoration = d.Decorate(hoveredItem);
return new[] { decoration }
.Concat(decoration.ExtraDecorations ?? Enumerable.Empty<Decoration>());
})
.ToArray();

if (decorations.Length == 0) {
Expand Down Expand Up @@ -95,7 +99,6 @@ private static void DrawToolTip(SpriteBatch b, Item? hoveredItem)
NumberSprite.draw(counter.Value, b, new Vector2(x, y), Color.White, scale, 1, 1, 0);
}


destinationRectangle.X += destinationRectangle.Width + Game1.pixelZoom;
}
}
Expand Down
2 changes: 1 addition & 1 deletion Informant/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"Name": "Informant",
"Author": "Slothsoft",
"Version": "1.5.3",
"Version": "1.5.5",
"Description": "Displays additional information on various objects.",
"UniqueID": "Slothsoft.Informant",
"EntryDll": "Informant.dll",
Expand Down

0 comments on commit f92e3ea

Please sign in to comment.