Fix party finder packet layout (#1875)

Co-authored-by: goat <16760685+goaaats@users.noreply.github.com>
This commit is contained in:
Infi 2024-07-02 18:39:18 +02:00 committed by GitHub
parent 87de538bf7
commit 39296124b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 56 additions and 30 deletions

View file

@ -13,34 +13,36 @@ namespace Dalamud.Game.Gui.PartyFinder.Internal;
internal readonly struct PartyFinderPacketListing internal readonly struct PartyFinderPacketListing
{ {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
private readonly byte[] header1; private readonly byte[] padding1;
internal readonly uint Id; internal readonly uint Id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
private readonly byte[] header2; private readonly byte[] padding2;
internal readonly uint ContentIdLower; internal readonly uint PaddingId;
private readonly ushort unknownShort1; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
private readonly ushort unknownShort2; private readonly byte[] padding3;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] internal readonly ulong ContentId;
private readonly byte[] header3;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
private readonly byte[] padding4;
internal readonly byte Category; internal readonly byte Category;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
private readonly byte[] header4; private readonly byte[] padding5;
internal readonly ushort Duty; internal readonly ushort Duty;
internal readonly byte DutyType; internal readonly byte DutyType;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
private readonly byte[] header5; private readonly byte[] padding6;
internal readonly ushort World; internal readonly ushort World;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
private readonly byte[] header6; private readonly byte[] padding7;
internal readonly byte Objective; internal readonly byte Objective;
internal readonly byte BeginnersWelcome; internal readonly byte BeginnersWelcome;
@ -49,36 +51,36 @@ internal readonly struct PartyFinderPacketListing
internal readonly byte LootRules; internal readonly byte LootRules;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
private readonly byte[] header7; // all zero in every pf I've examined private readonly byte[] padding8; // all zero in every pf I've examined
internal readonly uint LastPatchHotfixTimestamp; // last time the servers were restarted? internal readonly uint LastPatchHotfixTimestamp; // last time the servers were restarted?
internal readonly ushort SecondsRemaining; internal readonly ushort SecondsRemaining;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
private readonly byte[] header8; // 00 00 01 00 00 00 in every pf I've examined private readonly byte[] padding9; // 00 00 01 00 00 00 in every pf I've examined
internal readonly ushort MinimumItemLevel; internal readonly ushort MinimumItemLevel;
internal readonly ushort HomeWorld; internal readonly ushort HomeWorld;
internal readonly ushort CurrentWorld; internal readonly ushort CurrentWorld;
private readonly byte header9; private readonly byte padding10;
internal readonly byte NumSlots; internal readonly byte NumSlots;
internal readonly byte NumSlotsFilled;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] private readonly byte padding11;
private readonly byte[] header10;
internal readonly byte SearchArea; internal readonly byte SearchArea;
private readonly byte header11; private readonly byte padding12;
internal readonly byte NumParties; internal readonly byte NumParties;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
private readonly byte[] header12; // 00 00 00 always. maybe numParties is a u32? private readonly byte[] padding13; // 00 00 00 always. maybe numParties is a u32?
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
internal readonly uint[] Slots; internal readonly ulong[] Slots;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
internal readonly byte[] JobsPresent; internal readonly byte[] JobsPresent;
@ -90,6 +92,9 @@ internal readonly struct PartyFinderPacketListing
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 192)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 192)]
internal readonly byte[] Description; 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

View file

@ -18,7 +18,7 @@ namespace Dalamud.Game.Gui.PartyFinder;
internal sealed class PartyFinderGui : IInternalDisposableService, IPartyFinderGui internal sealed class PartyFinderGui : IInternalDisposableService, IPartyFinderGui
{ {
private readonly PartyFinderAddressResolver address; private readonly PartyFinderAddressResolver address;
private readonly IntPtr memory; private readonly nint memory;
private readonly Hook<ReceiveListingDelegate> receiveListingHook; private readonly Hook<ReceiveListingDelegate> receiveListingHook;
@ -39,7 +39,7 @@ internal sealed class PartyFinderGui : IInternalDisposableService, IPartyFinderG
} }
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate void ReceiveListingDelegate(IntPtr managerPtr, IntPtr data); private delegate void ReceiveListingDelegate(nint managerPtr, nint data);
/// <inheritdoc/> /// <inheritdoc/>
public event IPartyFinderGui.PartyFinderListingEventDelegate? ReceiveListing; public event IPartyFinderGui.PartyFinderListingEventDelegate? ReceiveListing;
@ -61,7 +61,7 @@ internal sealed class PartyFinderGui : IInternalDisposableService, IPartyFinderG
} }
} }
private void HandleReceiveListingDetour(IntPtr managerPtr, IntPtr data) private void HandleReceiveListingDetour(nint managerPtr, nint data)
{ {
try try
{ {
@ -75,7 +75,7 @@ internal sealed class PartyFinderGui : IInternalDisposableService, IPartyFinderG
this.receiveListingHook.Original(managerPtr, data); this.receiveListingHook.Original(managerPtr, data);
} }
private void HandleListingEvents(IntPtr data) private void HandleListingEvents(nint data)
{ {
var dataPtr = data + 0x10; var dataPtr = data + 0x10;

View file

@ -150,4 +150,14 @@ public enum JobFlags
/// Sage (SGE). /// Sage (SGE).
/// </summary> /// </summary>
Sage = 1 << 29, Sage = 1 << 29,
/// <summary>
/// Viper (VPR).
/// </summary>
Viper = 1 << 30,
/// <summary>
/// Pictomancer (PCT).
/// </summary>
Pictomancer = 1 << 31,
} }

View file

@ -49,6 +49,8 @@ public static class JobFlagsExtensions
JobFlags.Dancer => 38, JobFlags.Dancer => 38,
JobFlags.Reaper => 39, JobFlags.Reaper => 39,
JobFlags.Sage => 40, JobFlags.Sage => 40,
JobFlags.Viper => 41,
JobFlags.Pictomancer => 42,
_ => null, _ => null,
}; };

View file

@ -58,7 +58,7 @@ public interface IPartyFinderListing
/// <summary> /// <summary>
/// Gets the lower bits of the player's content ID. /// Gets the lower bits of the player's content ID.
/// </summary> /// </summary>
uint ContentIdLower { get; } ulong ContentId { get; }
/// <summary> /// <summary>
/// Gets the name of the player hosting this listing. /// Gets the name of the player hosting this listing.
@ -131,6 +131,11 @@ public interface IPartyFinderListing
/// </summary> /// </summary>
byte SlotsAvailable { get; } byte SlotsAvailable { get; }
/// <summary>
/// Gets the number of player slots filled.
/// </summary>
byte SlotsFilled { get; }
/// <summary> /// <summary>
/// Gets the time at which the server this listings is on last restarted for a patch/hotfix. /// Gets the time at which the server this listings is on last restarted for a patch/hotfix.
/// Probably. /// Probably.
@ -208,7 +213,7 @@ internal class PartyFinderListing : IPartyFinderListing
this.jobsPresent = listing.JobsPresent; this.jobsPresent = listing.JobsPresent;
this.Id = listing.Id; this.Id = listing.Id;
this.ContentIdLower = listing.ContentIdLower; this.ContentId = listing.ContentId;
this.Name = SeString.Parse(listing.Name.TakeWhile(b => b != 0).ToArray()); this.Name = SeString.Parse(listing.Name.TakeWhile(b => b != 0).ToArray());
this.Description = SeString.Parse(listing.Description.TakeWhile(b => b != 0).ToArray()); this.Description = SeString.Parse(listing.Description.TakeWhile(b => b != 0).ToArray());
this.World = new Lazy<World>(() => dataManager.GetExcelSheet<World>().GetRow(listing.World)); this.World = new Lazy<World>(() => dataManager.GetExcelSheet<World>().GetRow(listing.World));
@ -223,6 +228,7 @@ internal class PartyFinderListing : IPartyFinderListing
this.MinimumItemLevel = listing.MinimumItemLevel; this.MinimumItemLevel = listing.MinimumItemLevel;
this.Parties = listing.NumParties; this.Parties = listing.NumParties;
this.SlotsAvailable = listing.NumSlots; this.SlotsAvailable = listing.NumSlots;
this.SlotsFilled = listing.NumSlotsFilled;
this.LastPatchHotfixTimestamp = listing.LastPatchHotfixTimestamp; this.LastPatchHotfixTimestamp = listing.LastPatchHotfixTimestamp;
this.JobsPresent = listing.JobsPresent this.JobsPresent = listing.JobsPresent
.Select(id => new Lazy<ClassJob>( .Select(id => new Lazy<ClassJob>(
@ -236,7 +242,7 @@ internal class PartyFinderListing : IPartyFinderListing
public uint Id { get; } public uint Id { get; }
/// <inheritdoc/> /// <inheritdoc/>
public uint ContentIdLower { get; } public ulong ContentId { get; }
/// <inheritdoc/> /// <inheritdoc/>
public SeString Name { get; } public SeString Name { get; }
@ -280,6 +286,9 @@ internal class PartyFinderListing : IPartyFinderListing
/// <inheritdoc/> /// <inheritdoc/>
public byte SlotsAvailable { get; } public byte SlotsAvailable { get; }
/// <inheritdoc/>
public byte SlotsFilled { get; }
/// <inheritdoc/> /// <inheritdoc/>
public uint LastPatchHotfixTimestamp { get; } public uint LastPatchHotfixTimestamp { get; }
@ -325,5 +334,5 @@ internal class PartyFinderListing : IPartyFinderListing
public bool this[SearchAreaFlags flag] => this.searchArea == 0 || (this.searchArea & (uint)flag) > 0; public bool this[SearchAreaFlags flag] => this.searchArea == 0 || (this.searchArea & (uint)flag) > 0;
#endregion #endregion
} }

View file

@ -8,14 +8,14 @@ namespace Dalamud.Game.Gui.PartyFinder.Types;
/// </summary> /// </summary>
public class PartyFinderSlot public class PartyFinderSlot
{ {
private readonly uint accepting; private readonly ulong accepting;
private JobFlags[] listAccepting; private JobFlags[] listAccepting;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PartyFinderSlot"/> class. /// Initializes a new instance of the <see cref="PartyFinderSlot"/> class.
/// </summary> /// </summary>
/// <param name="accepting">The flag value of accepted jobs.</param> /// <param name="accepting">The flag value of accepted jobs.</param>
internal PartyFinderSlot(uint accepting) internal PartyFinderSlot(ulong accepting)
{ {
this.accepting = accepting; this.accepting = accepting;
} }