Skip to content

Commit d4207da

Browse files
feat: More convenient API
1 parent e231dfc commit d4207da

3 files changed

Lines changed: 53 additions & 25 deletions

File tree

src/D2SSharp.Tests/ConversionBinaryTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ private int CompareSections(string name1, byte[] data1, uint version1,
205205
return differences;
206206
}
207207

208-
private List<(string Name, int ByteOffset)> ParseSectionPositions(byte[] data, uint version)
208+
private List<(string Name, int ByteOffset)> ParseSectionPositions(ReadOnlySpan<byte> data, uint version)
209209
{
210210
var positions = new List<(string Name, int ByteOffset)>();
211211
var reader = new BitReader(data);

src/D2SSharp/Model/D2SaveOverlay.cs

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -595,25 +595,11 @@ public static ref D2SaveLayout From(Span<byte> data)
595595
return ref layout;
596596
}
597597

598-
/// <summary>
599-
/// Gets a reference to the layout from a byte array.
600-
/// Throws InvalidDataException if magic values are invalid or version is >= 104.
601-
/// For v104+ saves, use <see cref="D2SaveLayoutV104.From(byte[])"/> instead.
602-
/// </summary>
603-
public static ref D2SaveLayout From(byte[] data)
604-
=> ref From(data.AsSpan());
605-
606598
/// <summary>
607599
/// Updates the checksum in the provided data buffer.
608600
/// </summary>
609601
public static void UpdateChecksum(Span<byte> data)
610602
=> ChecksumCalculator.Update(data);
611-
612-
/// <summary>
613-
/// Updates the checksum in the provided data buffer.
614-
/// </summary>
615-
public static void UpdateChecksum(byte[] data)
616-
=> ChecksumCalculator.Update(data.AsSpan());
617603
}
618604

619605
/// <summary>
@@ -665,22 +651,45 @@ public static ref D2SaveLayoutV104 From(Span<byte> data)
665651
return ref layout;
666652
}
667653

668-
/// <summary>
669-
/// Gets a reference to the layout from a byte array.
670-
/// Throws InvalidDataException if magic values are invalid or version is &lt; 104.
671-
/// </summary>
672-
public static ref D2SaveLayoutV104 From(byte[] data)
673-
=> ref From(data.AsSpan());
674-
675654
/// <summary>
676655
/// Updates the checksum in the provided data buffer.
677656
/// </summary>
678657
public static void UpdateChecksum(Span<byte> data)
679658
=> ChecksumCalculator.Update(data);
659+
}
660+
661+
/// <summary>
662+
/// Blittable layout for the fixed 64-byte header of a shared stash tab.
663+
/// Provides zero-copy access to tab header fields without parsing items.
664+
/// </summary>
665+
[StructLayout(LayoutKind.Explicit, Size = Size)]
666+
public unsafe struct D2StashTabLayout
667+
{
668+
/// <summary>Size of the stash tab header in bytes.</summary>
669+
public const int Size = 64;
670+
671+
[FieldOffset(0)] public uint Magic;
672+
[FieldOffset(4)] public uint StashFormat;
673+
[FieldOffset(8)] public uint ItemFormat;
674+
[FieldOffset(12)] public uint Gold;
675+
[FieldOffset(16)] public ushort TabSize;
676+
[FieldOffset(18)] public ushort Season;
677+
[FieldOffset(20)] public StashTabType TabType;
678+
[FieldOffset(21)] private fixed byte _reserved[43];
679+
680+
private readonly bool IsValid => Magic == D2StashTab.Magic;
680681

681682
/// <summary>
682-
/// Updates the checksum in the provided data buffer.
683+
/// Gets a reference to the layout from a byte span at the given offset.
683684
/// </summary>
684-
public static void UpdateChecksum(byte[] data)
685-
=> ChecksumCalculator.Update(data.AsSpan());
685+
public static ref D2StashTabLayout From(Span<byte> data, int offset = 0)
686+
{
687+
if (data.Length - offset < Size)
688+
throw new InvalidDataException($"Data too small for stash tab header: {data.Length - offset} bytes, need {Size}.");
689+
ref var layout = ref MemoryMarshal.AsRef<D2StashTabLayout>(data[offset..]);
690+
if (!layout.IsValid)
691+
throw new InvalidDataException($"Invalid stash tab magic: 0x{layout.Magic:X8}, expected 0x{D2StashTab.Magic:X8}");
692+
return ref layout;
693+
}
694+
686695
}

src/D2SSharp/Model/D2StashTab.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,25 @@ public partial class D2StashTab
4242
/// <summary>Chronicle data (for Chronicle tabs only).</summary>
4343
public ChronicleSection? Chronicle { get; set; }
4444

45+
/// <summary>
46+
/// Reads a single stash tab from a byte span using the default external data.
47+
/// </summary>
48+
/// <param name="data">The stash tab data.</param>
49+
/// <returns>The parsed stash tab.</returns>
50+
public static D2StashTab Read(ReadOnlySpan<byte> data) => Read(data, TxtFileExternalData.Default);
51+
52+
/// <summary>
53+
/// Reads a single stash tab from a byte span.
54+
/// </summary>
55+
/// <param name="data">The stash tab data.</param>
56+
/// <param name="externalData">External game data for parsing items.</param>
57+
/// <returns>The parsed stash tab.</returns>
58+
public static D2StashTab Read(ReadOnlySpan<byte> data, IExternalData externalData)
59+
{
60+
var reader = new BitReader(data);
61+
return Read(ref reader, externalData);
62+
}
63+
4564
/// <summary>
4665
/// Reads a single stash tab from a BitReader.
4766
/// </summary>

0 commit comments

Comments
 (0)