mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-02-19 22:37:43 +01:00
Fix party finder packet layout (#1875)
Co-authored-by: goat <16760685+goaaats@users.noreply.github.com>
This commit is contained in:
parent
87de538bf7
commit
39296124b1
6 changed files with 56 additions and 30 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue