feat: add job filtering

This commit is contained in:
Anna 2021-01-15 18:47:13 -05:00
parent d910f5fbe6
commit 0f93fca760
4 changed files with 166 additions and 5 deletions

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace BetterPartyFinder {
@ -74,6 +75,60 @@ namespace BetterPartyFinder {
return false;
}
// filter based on jobs (slow?)
if (filter.Jobs.Count > 0) {
var slots = listing.Slots.ToArray();
var present = listing.RawJobsPresent.ToArray();
// create a list of sets containing the slots each job is able to join
var jobs = new HashSet<int>[filter.Jobs.Count];
for (var i = 0; i < jobs.Length; i++) {
jobs[i] = new HashSet<int>();
}
for (var idx = 0; idx < filter.Jobs.Count; idx++) {
var wanted = filter.Jobs[idx];
for (var i = 0; i < listing.SlotsAvailable; i++) {
// if the slot isn't already full and the job can fit into it, add it to the set
if (present[i] == 0 && slots[i][wanted]) {
jobs[idx].Add(i);
}
}
// if this job couldn't match any slot, can't join the party
if (jobs[idx].Count == 0) {
return false;
}
}
// loop through each unique pair of jobs
for (var i = 0; i < jobs.Length; i++) {
// ReSharper disable once LoopCanBeConvertedToQuery
for (var j = 0; j < jobs.Length; j++) {
if (i >= j) {
continue;
}
var a = jobs[i];
var b = jobs[j];
// check if the slots either job can join have overlap
var overlap = a.Intersect(b);
if (!overlap.Any()) {
continue;
}
// if there is overlap, check the difference between the sets
// if there is no difference, the party can't be joined
var difference = a.Except(b);
if (!difference.Any()) {
return false;
}
}
}
}
return true;
}

View File

@ -19,6 +19,7 @@ namespace BetterPartyFinder {
public bool BeginnersWelcome { get; }
public ushort SecondsRemaining { get; }
public ushort MinimumItemLevel { get; }
public byte SlotsAvailable { get; }
public IReadOnlyCollection<PartyFinderSlot> Slots => this._slots;
private readonly byte _objective;
@ -67,6 +68,7 @@ namespace BetterPartyFinder {
this.BeginnersWelcome = listing.beginnersWelcome == 1;
this.SecondsRemaining = listing.secondsRemaining;
this.MinimumItemLevel = listing.minimumItemLevel;
this.SlotsAvailable = listing.numSlots;
this._objective = listing.objective;
this._conditions = listing.conditions;
@ -127,7 +129,7 @@ namespace BetterPartyFinder {
Lancer = 1 << 4,
Archer = 1 << 5,
Conjurer = 1 << 6,
Thamaturge = 1 << 7,
Thaumaturge = 1 << 7,
Paladin = 1 << 8,
Monk = 1 << 9,
Warrior = 1 << 10,
@ -150,6 +152,45 @@ namespace BetterPartyFinder {
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,

View File

@ -71,13 +71,17 @@ namespace BetterPartyFinder {
internal readonly ushort homeWorld;
internal readonly ushort currentWorld;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
private readonly byte[] header9; // 02 XX 01 00 in every pf I've examined
private readonly byte header9;
internal readonly byte numSlots;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
private readonly byte[] header10;
internal readonly byte searchArea;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
private readonly byte[] header10; // 00 01 00 00 00 for every pf except alliance raids where it's 01 03 00 00 00 (second byte # parties?)
private readonly byte[] header11; // 00 01 00 00 00 for every pf except alliance raids where it's 01 03 00 00 00 (second byte # parties?)
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
internal readonly uint[] slots;

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Data;
@ -26,6 +27,8 @@ namespace BetterPartyFinder {
private string PresetName { get; set; } = string.Empty;
private bool[] _openSlots = new bool[8];
internal PluginUi(Plugin plugin) {
this.Plugin = plugin;
@ -295,7 +298,65 @@ namespace BetterPartyFinder {
return;
}
ImGui.TextUnformatted("Nothing here yet");
if (ImGui.Button("Add slot")) {
filter.Jobs.Add(0);
this.Plugin.Config.Save();
}
var toRemove = new HashSet<int>();
for (var i = 0; i < filter.Jobs.Count; i++) {
var slot = filter.Jobs[i];
if (!ImGui.CollapsingHeader($"Slot {i + 1}")) {
continue;
}
if (ImGui.Button("Select all")) {
filter.Jobs[i] = Enum.GetValues(typeof(JobFlags))
.Cast<JobFlags>()
.Aggregate(slot, (current, job) => current | job);
this.Plugin.Config.Save();
}
ImGui.SameLine();
if (ImGui.Button("Clear")) {
filter.Jobs[i] = 0;
this.Plugin.Config.Save();
}
ImGui.SameLine();
if (ImGui.Button("Delete")) {
toRemove.Add(i);
}
foreach (var job in (JobFlags[]) Enum.GetValues(typeof(JobFlags))) {
var selected = (slot & job) > 0;
if (!ImGui.Selectable(job.ClassJob(this.Plugin.Interface.Data)?.Name ?? "???", ref selected)) {
continue;
}
if (selected) {
slot |= job;
} else {
slot &= ~job;
}
filter.Jobs[i] = slot;
this.Plugin.Config.Save();
}
}
foreach (var idx in toRemove) {
filter.Jobs.RemoveAt(idx);
}
if (toRemove.Count > 0) {
this.Plugin.Config.Save();
}
ImGui.EndTabItem();
}