Fix PartyFinderListingPacket marshaling issues (#1884)

This commit is contained in:
Infi 2024-07-03 00:08:39 +02:00 committed by GitHub
parent 64a094f225
commit cf515cbc35
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 92 additions and 75 deletions

View file

@ -9,8 +9,8 @@ namespace Dalamud.Game.Gui.PartyFinder.Internal;
[SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "Sequential struct marshaling.")] [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "Sequential struct marshaling.")]
[SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:Elements should be ordered by access", Justification = "Sequential struct marshaling.")] [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:Elements should be ordered by access", Justification = "Sequential struct marshaling.")]
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Document the field usage.")] [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Document the field usage.")]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential, Pack = 1)]
internal readonly struct PartyFinderPacket internal unsafe struct PartyFinderPacket
{ {
/// <summary> /// <summary>
/// Gets the size of this packet. /// Gets the size of this packet.
@ -19,8 +19,7 @@ internal readonly struct PartyFinderPacket
internal readonly int BatchNumber; internal readonly int BatchNumber;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] private fixed byte paddingOuter[0x8];
private readonly byte[] padding1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
internal readonly PartyFinderPacketListing[] Listings; internal readonly PartyFinderPacketListing[] Listings;

View file

@ -9,95 +9,113 @@ namespace Dalamud.Game.Gui.PartyFinder.Internal;
/// </summary> /// </summary>
[SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:Elements should be ordered by access", Justification = "Sequential struct marshaling.")] [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:Elements should be ordered by access", Justification = "Sequential struct marshaling.")]
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Document the field usage.")] [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Document the field usage.")]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential, Pack = 1)]
internal readonly struct PartyFinderPacketListing internal unsafe struct PartyFinderPacketListing
{ {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] private fixed byte padding1[4];
private readonly byte[] padding1; internal uint Id;
internal readonly uint Id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] private fixed byte padding2[4];
private readonly byte[] padding2; internal uint PaddingId;
internal readonly uint PaddingId; private fixed byte padding3[4];
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] internal ulong ContentId;
private readonly byte[] padding3;
internal readonly ulong ContentId; private fixed byte padding4[4];
internal byte Category;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] private fixed byte padding5[3];
private readonly byte[] padding4; internal ushort Duty;
internal byte DutyType;
internal readonly byte Category; private fixed byte padding6[11];
internal ushort World;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] private fixed byte padding7[8];
private readonly byte[] padding5; internal byte Objective;
internal byte BeginnersWelcome;
internal byte Conditions;
internal byte DutyFinderSettings;
internal byte LootRules;
internal readonly ushort Duty; private fixed byte padding8[3];
internal readonly byte DutyType; internal uint LastPatchHotfixTimestamp; // last time the servers were restarted?
internal ushort SecondsRemaining;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] private fixed byte padding9[6];
private readonly byte[] padding6; internal ushort MinimumItemLevel;
internal ushort HomeWorld;
internal ushort CurrentWorld;
internal readonly ushort World; private byte padding10;
internal byte NumSlots;
internal byte NumSlotsFilled;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] private byte padding11;
private readonly byte[] padding7; internal byte SearchArea;
internal readonly byte Objective; private byte padding12;
internal readonly byte BeginnersWelcome; internal byte NumParties;
internal readonly byte Conditions;
internal readonly byte DutyFinderSettings;
internal readonly byte LootRules;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] private fixed byte padding13[7];
private readonly byte[] padding8; // all zero in every pf I've examined private fixed ulong slots[8];
private fixed byte jobsPresent[8];
private fixed byte name[32];
private fixed byte description[192];
internal readonly uint LastPatchHotfixTimestamp; // last time the servers were restarted? private fixed byte padding14[4];
internal readonly ushort SecondsRemaining;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
private readonly byte[] padding9; // 00 00 01 00 00 00 in every pf I've examined
internal readonly ushort MinimumItemLevel;
internal readonly ushort HomeWorld;
internal readonly ushort CurrentWorld;
private readonly byte padding10;
internal readonly byte NumSlots;
internal readonly byte NumSlotsFilled;
private readonly byte padding11;
internal readonly byte SearchArea;
private readonly byte padding12;
internal readonly byte NumParties;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
private readonly byte[] padding13; // 00 00 00 always. maybe numParties is a u32?
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
internal readonly ulong[] Slots;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
internal readonly byte[] JobsPresent;
// Note that ByValTStr will not work here because the strings are UTF-8 and there's only a CharSet for UTF-16 in C#.
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
internal readonly byte[] Name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 192)]
internal readonly byte[] Description;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
private readonly byte[] padding14;
internal bool IsNull() internal bool IsNull()
{ {
// a valid party finder must have at least one slot set // a valid party finder must have at least one slot set
return this.Slots.All(slot => slot == 0); return this.Slots.All(slot => slot == 0);
} }
#region Helper
internal ulong[] Slots
{
get
{
fixed (ulong* ptr = this.slots)
{
return new ReadOnlySpan<ulong>(ptr, 8).ToArray();
}
}
}
internal byte[] JobsPresent
{
get
{
fixed (byte* ptr = this.jobsPresent)
{
return new ReadOnlySpan<byte>(ptr, 8).ToArray();
}
}
}
internal byte[] Name
{
get
{
fixed (byte* ptr = this.name)
{
return new ReadOnlySpan<byte>(ptr, 32).ToArray();
}
}
}
internal byte[] Description
{
get
{
fixed (byte* ptr = this.description)
{
return new ReadOnlySpan<byte>(ptr, 192).ToArray();
}
}
}
#endregion
} }