feat: Adds item graphic size to Bounds.bin and makes item graphic offset available to gumps (#2115)
This commit is contained in:
parent
772511d1e8
commit
40479c946a
12 changed files with 96 additions and 50 deletions
Binary file not shown.
BIN
Distribution/Data/Items/ItemBounds.bin
Normal file
BIN
Distribution/Data/Items/ItemBounds.bin
Normal file
Binary file not shown.
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2024 - ModernUO Development Team *
|
* Copyright 2019-2025 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: ArtData.cs *
|
* File: ArtData.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -50,18 +50,18 @@ public class ArtData : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rectangle2D GetStaticBounds(int index)
|
public (ushort Width, ushort Height, Rectangle2D Bounds) GetStaticBounds(int index)
|
||||||
{
|
{
|
||||||
if (index is < 0 or > 0x10000)
|
if (index is < 0 or > 0x10000)
|
||||||
{
|
{
|
||||||
return Rectangle2D.Empty;
|
return (0, 0, Rectangle2D.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
index += 16384;
|
index += 16384;
|
||||||
|
|
||||||
if (!_dataRanges.TryGetValue(index, out var entry))
|
if (!_dataRanges.TryGetValue(index, out var entry))
|
||||||
{
|
{
|
||||||
return Rectangle2D.Empty;
|
return (0, 0, Rectangle2D.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
Span<ushort> buffer = stackalloc ushort[entry.Size / 2];
|
Span<ushort> buffer = stackalloc ushort[entry.Size / 2];
|
||||||
|
|
@ -73,10 +73,10 @@ public class ArtData : IDisposable
|
||||||
|
|
||||||
if (width == 0 || height == 0)
|
if (width == 0 || height == 0)
|
||||||
{
|
{
|
||||||
return Rectangle2D.Empty;
|
return (0, 0, Rectangle2D.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetBoundsFromRGBA1555Bitmap(width, height, buffer[4..]);
|
return (width, height, GetBoundsFromRGBA1555Bitmap(width, height, buffer[4..]));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<int, UOPEntry> LoadMulRanges(string idxPath)
|
private static Dictionary<int, UOPEntry> LoadMulRanges(string idxPath)
|
||||||
|
|
|
||||||
|
|
@ -2346,7 +2346,7 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var bounds = ItemBounds.Table[itemID & 0x3FFF];
|
var bounds = ItemBounds.Bounds[itemID & 0x3FFF];
|
||||||
|
|
||||||
if (doubled)
|
if (doubled)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2023 - ModernUO Development Team *
|
* Copyright 2019-2025 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: ItemBounds.cs *
|
* File: ItemBounds.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -17,13 +17,15 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Server.Logging;
|
using Server.Logging;
|
||||||
|
using Size = System.ValueTuple<ushort, ushort>;
|
||||||
|
|
||||||
namespace Server;
|
namespace Server;
|
||||||
|
|
||||||
public static class ItemBounds
|
public static class ItemBounds
|
||||||
{
|
{
|
||||||
private static readonly ILogger logger = LogFactory.GetLogger(typeof(ItemBounds));
|
private static readonly ILogger logger = LogFactory.GetLogger(typeof(ItemBounds));
|
||||||
private static readonly string _pathToBounds = Path.Combine(Core.BaseDirectory, "Data", "Binary", "Bounds.bin");
|
private const string _boundsFileName = "ItemBounds.bin";
|
||||||
|
private static readonly string _boundsFolder = Path.Combine(Core.BaseDirectory, "Data", "Items");
|
||||||
private static bool _isGenerating;
|
private static bool _isGenerating;
|
||||||
|
|
||||||
public static void Configure()
|
public static void Configure()
|
||||||
|
|
@ -32,7 +34,7 @@ public static class ItemBounds
|
||||||
}
|
}
|
||||||
|
|
||||||
[Usage("GenBounds")]
|
[Usage("GenBounds")]
|
||||||
[Description("Asynchronously generates the bounds.bin file from art.mul/artidx.mul or artLegacyMUL.uop to determine container boundaries.")]
|
[Description("Asynchronously generates the ItemBounds.bin file from art.mul/artidx.mul or artLegacyMUL.uop to determine graphic sizes and boundaries.")]
|
||||||
private static void GenBounds_OnCommand(CommandEventArgs e)
|
private static void GenBounds_OnCommand(CommandEventArgs e)
|
||||||
{
|
{
|
||||||
GenerateBoundsFileAsync(e.Mobile);
|
GenerateBoundsFileAsync(e.Mobile);
|
||||||
|
|
@ -40,19 +42,20 @@ public static class ItemBounds
|
||||||
|
|
||||||
static ItemBounds()
|
static ItemBounds()
|
||||||
{
|
{
|
||||||
Table = new Rectangle2D[TileData.ItemTable.Length];
|
if (!File.Exists(Path.Combine(_boundsFolder, _boundsFileName)))
|
||||||
|
|
||||||
if (!File.Exists(_pathToBounds))
|
|
||||||
{
|
{
|
||||||
logger.Information("Generating {BoundsFilePath}...", "Bounds.bin");
|
logger.Information("Generating {BoundsFilePath}...", _boundsFileName);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
GenerateBoundsFile();
|
GenerateBoundsFile(out var sizes, out var bounds);
|
||||||
logger.Information("Generated {BoundsFilePath} successfully.", "Bounds.bin");
|
Sizes = sizes;
|
||||||
|
Bounds = bounds;
|
||||||
|
|
||||||
|
logger.Information("Generated {BoundsFilePath} successfully.", _boundsFileName);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.Error(ex, "Failed to generate {BoundsFilePath}", "Bounds.bin");
|
logger.Error(ex, "Failed to generate {BoundsFilePath}", _boundsFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
@ -61,7 +64,9 @@ public static class ItemBounds
|
||||||
GenerateTable();
|
GenerateTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Rectangle2D[] Table { get; private set; }
|
public static Size[] Sizes { get; private set; }
|
||||||
|
|
||||||
|
public static Rectangle2D[] Bounds { get; private set; }
|
||||||
|
|
||||||
private static void GenerateBoundsFileAsync(Mobile m)
|
private static void GenerateBoundsFileAsync(Mobile m)
|
||||||
{
|
{
|
||||||
|
|
@ -76,16 +81,21 @@ public static class ItemBounds
|
||||||
state =>
|
state =>
|
||||||
{
|
{
|
||||||
var from = state as Mobile;
|
var from = state as Mobile;
|
||||||
logger.Information("Generating {BoundsFilePath}...", "Bounds.bin");
|
logger.Information("Generating {BoundsFilePath}...", _boundsFileName);
|
||||||
if (from != null)
|
if (from != null)
|
||||||
{
|
{
|
||||||
Core.LoopContext.Post(() => from?.SendMessage("Generating bounds file..."));
|
Core.LoopContext.Post(() => from.SendMessage("Generating bounds file..."));
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var table = GenerateBoundsFile();
|
GenerateBoundsFile(out var sizes, out var bounds);
|
||||||
Core.LoopContext.Post(() => Table = table);
|
Core.LoopContext.Post(() =>
|
||||||
|
{
|
||||||
|
Sizes = sizes;
|
||||||
|
Bounds = bounds;
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -93,21 +103,21 @@ public static class ItemBounds
|
||||||
{
|
{
|
||||||
Core.LoopContext.Post(() =>
|
Core.LoopContext.Post(() =>
|
||||||
{
|
{
|
||||||
from?.SendMessage("Failed to generate bounds file:");
|
from.SendMessage("Failed to generate bounds file:");
|
||||||
from?.SendMessage(ex.Message);
|
from.SendMessage(ex.Message);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Error(ex, "Failed to generate {BoundsFilePath}", "Bounds.bin");
|
logger.Error(ex, "Failed to generate {BoundsFilePath}", _boundsFileName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (from != null)
|
if (from != null)
|
||||||
{
|
{
|
||||||
Core.LoopContext.Post(
|
Core.LoopContext.Post(
|
||||||
() => from?.SendMessage(
|
() => from.SendMessage(
|
||||||
$"Bounds file saved to {Path.GetRelativePath(Core.BaseDirectory, _pathToBounds)}."
|
$"Bounds file saved to {Path.GetRelativePath(Core.BaseDirectory, Path.Combine(_boundsFolder, _boundsFileName))}."
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -119,48 +129,57 @@ public static class ItemBounds
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Rectangle2D[] GenerateBoundsFile()
|
private static void GenerateBoundsFile(out Size[] sizes, out Rectangle2D[] bounds)
|
||||||
{
|
{
|
||||||
var table = new Rectangle2D[TileData.ItemTable.Length];
|
bounds = new Rectangle2D[TileData.ItemTable.Length];
|
||||||
|
sizes = new Size[TileData.ItemTable.Length];
|
||||||
|
|
||||||
using var artData = new ArtData();
|
using var artData = new ArtData();
|
||||||
if (!artData.IsInitialized)
|
if (!artData.IsInitialized)
|
||||||
{
|
{
|
||||||
throw new FileNotFoundException("Unable to load art.mul/artidx.mul or artLegacyMUL.uop");
|
throw new FileNotFoundException("Unable to load art.mul/artidx.mul or artLegacyMUL.uop");
|
||||||
}
|
}
|
||||||
|
|
||||||
using var fs = new FileStream(_pathToBounds, FileMode.Create, FileAccess.Write);
|
PathUtility.EnsureDirectory(_boundsFolder);
|
||||||
|
using var fs = new FileStream(Path.Combine(_boundsFolder, _boundsFileName), FileMode.Create, FileAccess.Write);
|
||||||
using var bw = new BinaryWriter(fs);
|
using var bw = new BinaryWriter(fs);
|
||||||
|
|
||||||
for (var i = 0; i < table.Length; i++)
|
for (var i = 0; i < bounds.Length; i++)
|
||||||
{
|
{
|
||||||
var bounds = artData.GetStaticBounds(i);
|
var (w, h, b) = artData.GetStaticBounds(i);
|
||||||
|
|
||||||
bw.Write((short)bounds.X);
|
bw.Write(w);
|
||||||
bw.Write((short)bounds.Y);
|
bw.Write(h);
|
||||||
bw.Write((short)(bounds.X + bounds.Width + 1));
|
bw.Write((short)b.X);
|
||||||
bw.Write((short)(bounds.Y + bounds.Height + 1));
|
bw.Write((short)b.Y);
|
||||||
|
bw.Write((short)(b.X + b.Width + 1));
|
||||||
|
bw.Write((short)(b.Y + b.Height + 1));
|
||||||
|
|
||||||
table[i] = bounds;
|
bounds[i].Set(b.X, b.Y, b.Width, b.Height);
|
||||||
|
sizes[i] = (w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
return table;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GenerateTable()
|
private static void GenerateTable()
|
||||||
{
|
{
|
||||||
using var fs = new FileStream(_pathToBounds, FileMode.Open, FileAccess.Read, FileShare.Read);
|
Bounds = new Rectangle2D[TileData.ItemTable.Length];
|
||||||
|
Sizes = new Size[TileData.ItemTable.Length];
|
||||||
|
|
||||||
|
using var fs = new FileStream(Path.Combine(_boundsFolder, _boundsFileName), FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||||
using var bin = new BinaryReader(fs);
|
using var bin = new BinaryReader(fs);
|
||||||
|
|
||||||
var count = Math.Min(Table.Length, (int)(fs.Length / 8));
|
var count = Math.Min(Bounds.Length, (int)(fs.Length / 8));
|
||||||
|
|
||||||
for (var i = 0; i < count; ++i)
|
for (var i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
|
Sizes[i] = (bin.ReadUInt16(), bin.ReadUInt16());
|
||||||
|
|
||||||
int xMin = bin.ReadInt16();
|
int xMin = bin.ReadInt16();
|
||||||
int yMin = bin.ReadInt16();
|
int yMin = bin.ReadInt16();
|
||||||
int xMax = bin.ReadInt16();
|
int xMax = bin.ReadInt16();
|
||||||
int yMax = bin.ReadInt16();
|
int yMax = bin.ReadInt16();
|
||||||
|
|
||||||
Table[i].Set(xMin, yMin, xMax - xMin, yMax - yMin);
|
Bounds[i].Set(xMin, yMin, xMax - xMin, yMax - yMin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ namespace Server.Gumps
|
||||||
Console.WriteLine("Type {0} does not have a valid item id or shrink table entry.", obj.Type);
|
Console.WriteLine("Type {0} does not have a valid item id or shrink table entry.", obj.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
var bounds = ItemBounds.Table[itemID];
|
var bounds = ItemBounds.Bounds[itemID];
|
||||||
|
|
||||||
if (itemID != 1 && bounds.Height < EntryHeight * 2)
|
if (itemID != 1 && bounds.Height < EntryHeight * 2)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ public class SheriffGump : FactionGump
|
||||||
|
|
||||||
private void CenterItem(int itemID, int x, int y, int w, int h)
|
private void CenterItem(int itemID, int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
var rc = ItemBounds.Table[itemID];
|
var rc = ItemBounds.Bounds[itemID];
|
||||||
AddItem(x + (w - rc.Width) / 2 - rc.X, y + (h - rc.Height) / 2 - rc.Y, itemID);
|
AddItem(x + (w - rc.Width) / 2 - rc.X, y + (h - rc.Height) / 2 - rc.Y, itemID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* ModernUO *
|
* ModernUO *
|
||||||
* Copyright 2019-2024 - ModernUO Development Team *
|
* Copyright 2019-2025 - ModernUO Development Team *
|
||||||
* Email: hi@modernuo.com *
|
* Email: hi@modernuo.com *
|
||||||
* File: BaseGump.cs *
|
* File: BaseGump.cs *
|
||||||
* *
|
* *
|
||||||
|
|
@ -86,4 +86,31 @@ public abstract class BaseGump
|
||||||
return hash == 461 ? hash * primeMulti : hash;
|
return hash == 461 ? hash * primeMulti : hash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Point2D GetItemGraphicOffset(int itemId)
|
||||||
|
{
|
||||||
|
var (width, height) = ItemBounds.Sizes[itemId];
|
||||||
|
var x = 0;
|
||||||
|
var y = 0;
|
||||||
|
|
||||||
|
if (width > 44)
|
||||||
|
{
|
||||||
|
x -= (width - 44) / 2;
|
||||||
|
}
|
||||||
|
else if (width < 44)
|
||||||
|
{
|
||||||
|
x += (44 - width) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (height > 44)
|
||||||
|
{
|
||||||
|
y -= height - 44;
|
||||||
|
}
|
||||||
|
else if (height < 44)
|
||||||
|
{
|
||||||
|
y += 44 - height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Point2D(x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ namespace Server.Gumps
|
||||||
{
|
{
|
||||||
var entry = Rewards[i];
|
var entry = Rewards[i];
|
||||||
|
|
||||||
var bounds = ItemBounds.Table[entry.ItemID];
|
var bounds = ItemBounds.Bounds[entry.ItemID];
|
||||||
var height = Math.Max(36, bounds.Height);
|
var height = Math.Max(36, bounds.Height);
|
||||||
|
|
||||||
if (offset + height > 320)
|
if (offset + height > 320)
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ public partial class PlagueBeastBackpack : BaseContainer
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ir = ItemBounds.Table[item.ItemID];
|
var ir = ItemBounds.Bounds[item.ItemID];
|
||||||
int x, y;
|
int x, y;
|
||||||
var cx = p.X + ir.X + ir.Width / 2;
|
var cx = p.X + ir.X + ir.Width / 2;
|
||||||
var cy = p.Y + ir.Y + ir.Height / 2;
|
var cy = p.Y + ir.Y + ir.Height / 2;
|
||||||
|
|
@ -134,7 +134,7 @@ public partial class PlagueBeastBackpack : BaseContainer
|
||||||
{
|
{
|
||||||
if (Items[i] is PlagueBeastComponent innard)
|
if (Items[i] is PlagueBeastComponent innard)
|
||||||
{
|
{
|
||||||
var r = ItemBounds.Table[innard.ItemID];
|
var r = ItemBounds.Bounds[innard.ItemID];
|
||||||
|
|
||||||
x = innard.X + r.X;
|
x = innard.X + r.X;
|
||||||
y = innard.Y + r.Y;
|
y = innard.Y + r.Y;
|
||||||
|
|
|
||||||
|
|
@ -4733,7 +4733,7 @@ namespace Server.Mobiles
|
||||||
for (int i = _page * 4, y = 72; i < (_page + 1) * 4 && i < _items.Length; ++i, y += 75)
|
for (int i = _page * 4, y = 72; i < (_page + 1) * 4 && i < _items.Length; ++i, y += 75)
|
||||||
{
|
{
|
||||||
var item = _items[i];
|
var item = _items[i];
|
||||||
var b = ItemBounds.Table[item.ItemID];
|
var b = ItemBounds.Bounds[item.ItemID];
|
||||||
|
|
||||||
builder.AddImageTiledButton(
|
builder.AddImageTiledButton(
|
||||||
40,
|
40,
|
||||||
|
|
|
||||||
|
|
@ -422,7 +422,7 @@ public class AnimalForm : NinjaSpell
|
||||||
|
|
||||||
int y = Math.DivRem(pos, 2, out var rem) * 64 + 44;
|
int y = Math.DivRem(pos, 2, out var rem) * 64 + 44;
|
||||||
int x = rem == 0 ? 14 : 264;
|
int x = rem == 0 ? 14 : 264;
|
||||||
Rectangle2D b = ItemBounds.Table[entry.ItemID];
|
Rectangle2D b = ItemBounds.Bounds[entry.ItemID];
|
||||||
|
|
||||||
builder.AddImageTiledButton(x, y, 0x918, 0x919, i + 1, GumpButtonType.Reply, 0, entry.ItemID,
|
builder.AddImageTiledButton(x, y, 0x918, 0x919, i + 1, GumpButtonType.Reply, 0, entry.ItemID,
|
||||||
entry.Hue, 40 - b.Width / 2 - b.X, 30 - b.Height / 2 - b.Y, entry.Tooltip);
|
entry.Hue, 40 - b.Width / 2 - b.X, 30 - b.Height / 2 - b.Y, entry.Tooltip);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue