refactor: use new Dalamud PF event
This commit is contained in:
parent
a83bb75e21
commit
a3ce973dda
|
@ -8,7 +8,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Dalamud, Version=5.2.3.3, Culture=neutral, PublicKeyToken=null">
|
<Reference Include="Dalamud, Version=5.2.3.5, Culture=neutral, PublicKeyToken=null">
|
||||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Dalamud.dll</HintPath>
|
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Dalamud.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DalamudPackager" Version="1.2.0"/>
|
<PackageReference Include="DalamudPackager" Version="1.2.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Dalamud.Configuration;
|
using Dalamud.Configuration;
|
||||||
|
using Dalamud.Game.Internal.Gui.Structs;
|
||||||
|
|
||||||
namespace BetterPartyFinder {
|
namespace BetterPartyFinder {
|
||||||
public class Configuration : IPluginConfiguration {
|
public class Configuration : IPluginConfiguration {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Dalamud.Game.Internal.Gui;
|
||||||
|
using Dalamud.Game.Internal.Gui.Structs;
|
||||||
|
|
||||||
namespace BetterPartyFinder {
|
namespace BetterPartyFinder {
|
||||||
public class Filter : IDisposable {
|
public class Filter : IDisposable {
|
||||||
|
@ -9,7 +11,11 @@ namespace BetterPartyFinder {
|
||||||
internal Filter(Plugin plugin) {
|
internal Filter(Plugin plugin) {
|
||||||
this.Plugin = plugin;
|
this.Plugin = plugin;
|
||||||
|
|
||||||
this.Plugin.Functions.ReceivePartyFinderListing += this.ReceiveListing;
|
this.Plugin.Interface.Framework.Gui.PartyFinder.ReceiveListing += this.ReceiveListing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
this.Plugin.Interface.Framework.Gui.PartyFinder.ReceiveListing -= this.ReceiveListing;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReceiveListing(PartyFinderListing listing, PartyFinderListingEventArgs args) {
|
private void ReceiveListing(PartyFinderListing listing, PartyFinderListingEventArgs args) {
|
||||||
|
@ -142,16 +148,12 @@ namespace BetterPartyFinder {
|
||||||
|
|
||||||
// filter based on player
|
// filter based on player
|
||||||
if (filter.Players.Count > 0) {
|
if (filter.Players.Count > 0) {
|
||||||
if (filter.Players.Any(info => info.Name == listing.Name && info.World == listing.HomeWorld.Value.RowId)) {
|
if (filter.Players.Any(info => info.Name == listing.Name.TextValue && info.World == listing.HomeWorld.Value.RowId)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose() {
|
|
||||||
this.Plugin.Functions.ReceivePartyFinderListing -= this.ReceiveListing;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Dalamud.Hooking;
|
using Dalamud.Hooking;
|
||||||
using Dalamud.Plugin;
|
|
||||||
|
|
||||||
namespace BetterPartyFinder {
|
namespace BetterPartyFinder {
|
||||||
public class GameFunctions : IDisposable {
|
public class GameFunctions : IDisposable {
|
||||||
|
@ -14,18 +13,6 @@ namespace BetterPartyFinder {
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region PF Listings events
|
|
||||||
|
|
||||||
internal delegate void PartyFinderListingEventDelegate(PartyFinderListing listing, PartyFinderListingEventArgs args);
|
|
||||||
|
|
||||||
internal event PartyFinderListingEventDelegate? ReceivePartyFinderListing;
|
|
||||||
|
|
||||||
private delegate void HandlePfPacketDelegate(IntPtr param1, IntPtr data);
|
|
||||||
|
|
||||||
private readonly Hook<HandlePfPacketDelegate> _handlePacketHook;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private Plugin Plugin { get; }
|
private Plugin Plugin { get; }
|
||||||
private IntPtr PartyFinderAgent { get; set; } = IntPtr.Zero;
|
private IntPtr PartyFinderAgent { get; set; } = IntPtr.Zero;
|
||||||
|
|
||||||
|
@ -33,19 +20,14 @@ namespace BetterPartyFinder {
|
||||||
this.Plugin = plugin;
|
this.Plugin = plugin;
|
||||||
|
|
||||||
var requestPfPtr = this.Plugin.Interface.TargetModuleScanner.ScanText("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 40 0F 10 81 ?? ?? ?? ??");
|
var requestPfPtr = this.Plugin.Interface.TargetModuleScanner.ScanText("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 40 0F 10 81 ?? ?? ?? ??");
|
||||||
var listingPtr = this.Plugin.Interface.TargetModuleScanner.ScanText("40 53 41 57 48 83 EC 28 48 8B D9");
|
|
||||||
|
|
||||||
this._requestPartyFinderListings = Marshal.GetDelegateForFunctionPointer<RequestPartyFinderListingsDelegate>(requestPfPtr);
|
this._requestPartyFinderListings = Marshal.GetDelegateForFunctionPointer<RequestPartyFinderListingsDelegate>(requestPfPtr);
|
||||||
this._requestPfListingsHook = new Hook<RequestPartyFinderListingsDelegate>(requestPfPtr, new RequestPartyFinderListingsDelegate(this.OnRequestPartyFinderListings));
|
this._requestPfListingsHook = new Hook<RequestPartyFinderListingsDelegate>(requestPfPtr, new RequestPartyFinderListingsDelegate(this.OnRequestPartyFinderListings));
|
||||||
this._requestPfListingsHook.Enable();
|
this._requestPfListingsHook.Enable();
|
||||||
|
|
||||||
this._handlePacketHook = new Hook<HandlePfPacketDelegate>(listingPtr, new HandlePfPacketDelegate(this.PacketDetour));
|
|
||||||
this._handlePacketHook.Enable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose() {
|
public void Dispose() {
|
||||||
this._requestPfListingsHook.Dispose();
|
this._requestPfListingsHook.Dispose();
|
||||||
this._handlePacketHook.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte OnRequestPartyFinderListings(IntPtr agent, byte categoryIdx) {
|
private byte OnRequestPartyFinderListings(IntPtr agent, byte categoryIdx) {
|
||||||
|
@ -69,71 +51,5 @@ namespace BetterPartyFinder {
|
||||||
var categoryIdx = Marshal.ReadByte(this.PartyFinderAgent + categoryOffset);
|
var categoryIdx = Marshal.ReadByte(this.PartyFinderAgent + categoryOffset);
|
||||||
this._requestPartyFinderListings(this.PartyFinderAgent, categoryIdx);
|
this._requestPartyFinderListings(this.PartyFinderAgent, categoryIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void PacketDetour(IntPtr param1, IntPtr data) {
|
|
||||||
if (data == IntPtr.Zero) {
|
|
||||||
goto Return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.OnPacket(data);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
PluginLog.Error(ex, "Unhandled exception in PF packet detour");
|
|
||||||
}
|
|
||||||
|
|
||||||
Return:
|
|
||||||
this._handlePacketHook!.Original(param1, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPacket(IntPtr data) {
|
|
||||||
var dataPtr = data + 0x10;
|
|
||||||
|
|
||||||
// parse the packet into a struct
|
|
||||||
var packet = Marshal.PtrToStructure<PfPacket>(dataPtr);
|
|
||||||
|
|
||||||
var needToRewrite = false;
|
|
||||||
|
|
||||||
for (var i = 0; i < packet.listings.Length; i++) {
|
|
||||||
if (packet.listings[i].IsNull()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// invoke event for each non-null listing
|
|
||||||
var listing = new PartyFinderListing(packet.listings[i], this.Plugin.Interface.Data);
|
|
||||||
var args = new PartyFinderListingEventArgs();
|
|
||||||
this.ReceivePartyFinderListing?.Invoke(listing, args);
|
|
||||||
|
|
||||||
if (args.Visible) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// zero the listing if it shouldn't be visible
|
|
||||||
packet.listings[i] = new PfListing();
|
|
||||||
needToRewrite = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!needToRewrite) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get some memory for writing to
|
|
||||||
var newPacket = new byte[PacketInfo.PacketSize];
|
|
||||||
var pinnedArray = GCHandle.Alloc(newPacket, GCHandleType.Pinned);
|
|
||||||
var pointer = pinnedArray.AddrOfPinnedObject();
|
|
||||||
|
|
||||||
// write our struct into the memory (doing this directly crashes the game)
|
|
||||||
Marshal.StructureToPtr(packet, pointer, false);
|
|
||||||
|
|
||||||
// copy our new memory over the game's
|
|
||||||
Marshal.Copy(newPacket, 0, dataPtr, PacketInfo.PacketSize);
|
|
||||||
|
|
||||||
// free memory
|
|
||||||
pinnedArray.Free();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class PartyFinderListingEventArgs {
|
|
||||||
public bool Visible { get; set; } = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,242 +0,0 @@
|
||||||
using Dalamud.Data;
|
|
||||||
using Lumina.Excel.GeneratedSheets;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace BetterPartyFinder {
|
|
||||||
public class PartyFinderListing {
|
|
||||||
public uint Id { get; }
|
|
||||||
public string Name { get; }
|
|
||||||
public string Description { get; }
|
|
||||||
public Lazy<World> World { get; }
|
|
||||||
public Lazy<World> HomeWorld { get; }
|
|
||||||
public Lazy<World> CurrentWorld { get; }
|
|
||||||
public Category Category { get; }
|
|
||||||
public ushort RawDuty { get; }
|
|
||||||
public Lazy<ContentFinderCondition> Duty { get; }
|
|
||||||
public DutyType DutyType { get; }
|
|
||||||
public bool BeginnersWelcome { get; }
|
|
||||||
public ushort SecondsRemaining { get; }
|
|
||||||
public ushort MinimumItemLevel { get; }
|
|
||||||
public byte Parties { get; }
|
|
||||||
public byte SlotsAvailable { get; }
|
|
||||||
public IEnumerable<PartyFinderSlot> Slots => this._slots;
|
|
||||||
|
|
||||||
private readonly byte _objective;
|
|
||||||
public ObjectiveFlags Objective => (ObjectiveFlags) this._objective;
|
|
||||||
|
|
||||||
private readonly byte _conditions;
|
|
||||||
public ConditionFlags Conditions => (ConditionFlags) this._conditions;
|
|
||||||
|
|
||||||
private readonly byte _dutyFinderSettings;
|
|
||||||
public DutyFinderSettingsFlags DutyFinderSettings => (DutyFinderSettingsFlags) this._dutyFinderSettings;
|
|
||||||
|
|
||||||
private readonly byte _lootRules;
|
|
||||||
public LootRuleFlags LootRules => (LootRuleFlags) this._lootRules;
|
|
||||||
|
|
||||||
private readonly byte _searchArea;
|
|
||||||
public SearchAreaFlags SearchArea => (SearchAreaFlags) this._searchArea;
|
|
||||||
|
|
||||||
private readonly PartyFinderSlot[] _slots;
|
|
||||||
|
|
||||||
private readonly byte[] _jobsPresent;
|
|
||||||
internal IEnumerable<byte> RawJobsPresent => this._jobsPresent;
|
|
||||||
internal IReadOnlyCollection<Lazy<ClassJob?>> JobsPresent { get; }
|
|
||||||
|
|
||||||
public bool this[ObjectiveFlags flag] => this._objective == 0 || (this._objective & (uint) flag) > 0;
|
|
||||||
|
|
||||||
|
|
||||||
public bool this[ConditionFlags flag] => this._conditions == 0 || (this._conditions & (uint) flag) > 0;
|
|
||||||
|
|
||||||
public bool this[DutyFinderSettingsFlags flag] => this._dutyFinderSettings == 0 || (this._dutyFinderSettings & (uint) flag) > 0;
|
|
||||||
|
|
||||||
public bool this[LootRuleFlags flag] => this._lootRules == 0 || (this._lootRules & (uint) flag) > 0;
|
|
||||||
|
|
||||||
public bool this[SearchAreaFlags flag] => this._searchArea == 0 || (this._searchArea & (uint) flag) > 0;
|
|
||||||
|
|
||||||
internal PartyFinderListing(PfListing listing, DataManager dataManager) {
|
|
||||||
this.Id = listing.id;
|
|
||||||
this.Name = listing.Name();
|
|
||||||
this.Description = listing.Description();
|
|
||||||
this.World = new Lazy<World>(() => dataManager.GetExcelSheet<World>().GetRow(listing.world));
|
|
||||||
this.HomeWorld = new Lazy<World>(() => dataManager.GetExcelSheet<World>().GetRow(listing.homeWorld));
|
|
||||||
this.CurrentWorld = new Lazy<World>(() => dataManager.GetExcelSheet<World>().GetRow(listing.currentWorld));
|
|
||||||
this.Category = (Category) listing.category;
|
|
||||||
this.RawDuty = listing.duty;
|
|
||||||
this.Duty = new Lazy<ContentFinderCondition>(() => dataManager.GetExcelSheet<ContentFinderCondition>().GetRow(listing.duty));
|
|
||||||
this.DutyType = (DutyType) listing.dutyType;
|
|
||||||
this.BeginnersWelcome = listing.beginnersWelcome == 1;
|
|
||||||
this.SecondsRemaining = listing.secondsRemaining;
|
|
||||||
this.MinimumItemLevel = listing.minimumItemLevel;
|
|
||||||
this.Parties = listing.numParties;
|
|
||||||
this.SlotsAvailable = listing.numSlots;
|
|
||||||
|
|
||||||
this._objective = listing.objective;
|
|
||||||
this._conditions = listing.conditions;
|
|
||||||
this._dutyFinderSettings = listing.dutyFinderSettings;
|
|
||||||
this._lootRules = listing.lootRules;
|
|
||||||
this._searchArea = listing.searchArea;
|
|
||||||
|
|
||||||
this._slots = listing.slots.Select(accepting => new PartyFinderSlot(accepting)).ToArray();
|
|
||||||
this._jobsPresent = listing.jobsPresent;
|
|
||||||
this.JobsPresent = this._jobsPresent
|
|
||||||
.Select(id => new Lazy<ClassJob?>(() => id == 0
|
|
||||||
? null
|
|
||||||
: dataManager.GetExcelSheet<ClassJob>().GetRow(id)))
|
|
||||||
.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PartyFinderSlot {
|
|
||||||
private readonly uint _accepting;
|
|
||||||
private JobFlags[]? _listAccepting;
|
|
||||||
|
|
||||||
public IReadOnlyCollection<JobFlags> Accepting {
|
|
||||||
get {
|
|
||||||
if (this._listAccepting != null) {
|
|
||||||
return this._listAccepting;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._listAccepting = Enum.GetValues(typeof(JobFlags))
|
|
||||||
.Cast<JobFlags>()
|
|
||||||
.Where(flag => this[flag])
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
return this._listAccepting;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool this[JobFlags flag] => (this._accepting & (uint) flag) > 0;
|
|
||||||
|
|
||||||
internal PartyFinderSlot(uint accepting) {
|
|
||||||
this._accepting = accepting;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum SearchAreaFlags : uint {
|
|
||||||
DataCentre = 1 << 0,
|
|
||||||
Private = 1 << 1,
|
|
||||||
AllianceRaid = 1 << 2,
|
|
||||||
World = 1 << 3,
|
|
||||||
OnePlayerPerJob = 1 << 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum JobFlags {
|
|
||||||
Gladiator = 1 << 1,
|
|
||||||
Pugilist = 1 << 2,
|
|
||||||
Marauder = 1 << 3,
|
|
||||||
Lancer = 1 << 4,
|
|
||||||
Archer = 1 << 5,
|
|
||||||
Conjurer = 1 << 6,
|
|
||||||
Thaumaturge = 1 << 7,
|
|
||||||
Paladin = 1 << 8,
|
|
||||||
Monk = 1 << 9,
|
|
||||||
Warrior = 1 << 10,
|
|
||||||
Dragoon = 1 << 11,
|
|
||||||
Bard = 1 << 12,
|
|
||||||
WhiteMage = 1 << 13,
|
|
||||||
BlackMage = 1 << 14,
|
|
||||||
Arcanist = 1 << 15,
|
|
||||||
Summoner = 1 << 16,
|
|
||||||
Scholar = 1 << 17,
|
|
||||||
Rogue = 1 << 18,
|
|
||||||
Ninja = 1 << 19,
|
|
||||||
Machinist = 1 << 20,
|
|
||||||
DarkKnight = 1 << 21,
|
|
||||||
Astrologian = 1 << 22,
|
|
||||||
Samurai = 1 << 23,
|
|
||||||
RedMage = 1 << 24,
|
|
||||||
BlueMage = 1 << 25,
|
|
||||||
Gunbreaker = 1 << 26,
|
|
||||||
Dancer = 1 << 27,
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static class JobFlagsExt {
|
|
||||||
internal static ClassJob? ClassJob(this JobFlags job, DataManager data) {
|
|
||||||
var jobs = data.GetExcelSheet<ClassJob>();
|
|
||||||
|
|
||||||
uint? row = job switch {
|
|
||||||
JobFlags.Gladiator => 1,
|
|
||||||
JobFlags.Pugilist => 2,
|
|
||||||
JobFlags.Marauder => 3,
|
|
||||||
JobFlags.Lancer => 4,
|
|
||||||
JobFlags.Archer => 5,
|
|
||||||
JobFlags.Conjurer => 6,
|
|
||||||
JobFlags.Thaumaturge => 7,
|
|
||||||
JobFlags.Paladin => 19,
|
|
||||||
JobFlags.Monk => 20,
|
|
||||||
JobFlags.Warrior => 21,
|
|
||||||
JobFlags.Dragoon => 22,
|
|
||||||
JobFlags.Bard => 23,
|
|
||||||
JobFlags.WhiteMage => 24,
|
|
||||||
JobFlags.BlackMage => 25,
|
|
||||||
JobFlags.Arcanist => 26,
|
|
||||||
JobFlags.Summoner => 27,
|
|
||||||
JobFlags.Scholar => 28,
|
|
||||||
JobFlags.Rogue => 29,
|
|
||||||
JobFlags.Ninja => 30,
|
|
||||||
JobFlags.Machinist => 31,
|
|
||||||
JobFlags.DarkKnight => 32,
|
|
||||||
JobFlags.Astrologian => 33,
|
|
||||||
JobFlags.Samurai => 34,
|
|
||||||
JobFlags.RedMage => 35,
|
|
||||||
JobFlags.BlueMage => 36,
|
|
||||||
JobFlags.Gunbreaker => 37,
|
|
||||||
JobFlags.Dancer => 38,
|
|
||||||
_ => null,
|
|
||||||
};
|
|
||||||
|
|
||||||
return row == null ? null : jobs.GetRow((uint) row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum ObjectiveFlags : uint {
|
|
||||||
None = 0,
|
|
||||||
DutyCompletion = 1,
|
|
||||||
Practice = 2,
|
|
||||||
Loot = 4,
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum ConditionFlags : uint {
|
|
||||||
None = 1,
|
|
||||||
DutyComplete = 2,
|
|
||||||
DutyIncomplete = 4,
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum DutyFinderSettingsFlags : uint {
|
|
||||||
None = 0,
|
|
||||||
UndersizedParty = 1 << 0,
|
|
||||||
MinimumItemLevel = 1 << 1,
|
|
||||||
SilenceEcho = 1 << 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum LootRuleFlags : uint {
|
|
||||||
None = 0,
|
|
||||||
GreedOnly = 1,
|
|
||||||
Lootmaster = 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Category {
|
|
||||||
Duty = 0,
|
|
||||||
QuestBattles = 1 << 0,
|
|
||||||
Fates = 1 << 1,
|
|
||||||
TreasureHunt = 1 << 2,
|
|
||||||
TheHunt = 1 << 3,
|
|
||||||
GatheringForays = 1 << 4,
|
|
||||||
DeepDungeons = 1 << 5,
|
|
||||||
AdventuringForays = 1 << 6,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum DutyType {
|
|
||||||
Other = 0,
|
|
||||||
Roulette = 1 << 0,
|
|
||||||
Normal = 1 << 1,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,125 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace BetterPartyFinder {
|
|
||||||
public static class PacketInfo {
|
|
||||||
public static readonly int PacketSize = Marshal.SizeOf<PfPacket>();
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public readonly struct PfPacket {
|
|
||||||
private readonly int unk0;
|
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
|
||||||
private readonly byte[] padding1;
|
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
|
||||||
public readonly PfListing[] listings;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public readonly struct PfListing {
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
|
||||||
private readonly byte[] header1;
|
|
||||||
|
|
||||||
internal readonly uint id;
|
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
|
||||||
private readonly byte[] header2;
|
|
||||||
|
|
||||||
private readonly uint unknownInt1;
|
|
||||||
private readonly ushort unknownShort1;
|
|
||||||
private readonly ushort unknownShort2;
|
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
|
|
||||||
private readonly byte[] header3;
|
|
||||||
|
|
||||||
internal readonly byte category;
|
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
|
||||||
private readonly byte[] header4;
|
|
||||||
|
|
||||||
internal readonly ushort duty;
|
|
||||||
internal readonly byte dutyType;
|
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
|
|
||||||
private readonly byte[] header5;
|
|
||||||
|
|
||||||
internal readonly ushort world;
|
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
|
||||||
private readonly byte[] header6;
|
|
||||||
|
|
||||||
internal readonly byte objective;
|
|
||||||
internal readonly byte beginnersWelcome;
|
|
||||||
internal readonly byte conditions;
|
|
||||||
internal readonly byte dutyFinderSettings;
|
|
||||||
internal readonly byte lootRules;
|
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
|
||||||
private readonly byte[] header7; // all zero in every pf I've examined
|
|
||||||
|
|
||||||
private readonly uint lastPatchHotfixTimestamp; // last time the servers were restarted?
|
|
||||||
internal readonly ushort secondsRemaining;
|
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
|
||||||
private readonly byte[] header8; // 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 header9;
|
|
||||||
|
|
||||||
internal readonly byte numSlots;
|
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
|
||||||
private readonly byte[] header10;
|
|
||||||
|
|
||||||
internal readonly byte searchArea;
|
|
||||||
|
|
||||||
private readonly byte header11;
|
|
||||||
|
|
||||||
internal readonly byte numParties;
|
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
|
||||||
private readonly byte[] header12; // 00 00 00 always. maybe numParties is a u32?
|
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
|
||||||
internal readonly uint[] 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)]
|
|
||||||
private readonly byte[] name;
|
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 192)]
|
|
||||||
private readonly byte[] description;
|
|
||||||
|
|
||||||
// 128 (0x80) before name and desc
|
|
||||||
// 160 (0xA0) with name (32 bytes/0x20)
|
|
||||||
// 352 (0x160) with both (192 bytes/0xC0)
|
|
||||||
|
|
||||||
private static string HandleString(IEnumerable<byte> bytes) {
|
|
||||||
var nonNull = bytes.TakeWhile(b => b != 0).ToArray();
|
|
||||||
return Encoding.UTF8.GetString(nonNull);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal string Name() {
|
|
||||||
return HandleString(this.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal string Description() {
|
|
||||||
return HandleString(this.description);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool IsNull() {
|
|
||||||
// a valid party finder must have at least one slot set
|
|
||||||
return this.slots.All(slot => slot == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,9 +3,11 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Dalamud.Data;
|
using Dalamud.Data;
|
||||||
|
using Dalamud.Game.Internal.Gui.Structs;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Lumina.Excel.GeneratedSheets;
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
using Addon = Lumina.Excel.GeneratedSheets.Addon;
|
||||||
using GameAddon = Dalamud.Game.Internal.Gui.Addon.Addon;
|
using GameAddon = Dalamud.Game.Internal.Gui.Addon.Addon;
|
||||||
|
|
||||||
namespace BetterPartyFinder {
|
namespace BetterPartyFinder {
|
||||||
|
|
Loading…
Reference in New Issue