Explorar el Código

Add IPC integration with XivEsp

Lilith Song hace 2 años
padre
commit
15babbcd76

+ 2 - 0
HuntBuddy/Configuration.cs

@@ -11,6 +11,8 @@ public class Configuration: IPluginConfiguration {
 		set;
 	}
 
+	public bool EnableXivEspIntegration;
+	public bool AutoSetEspSearchOnNextHuntCommand;
 	public bool IncludeAreaOnMap;
 	public bool LockWindowPositions;
 	public bool ShowLocalHunts;

+ 11 - 3
HuntBuddy/Ipc/ConsumerBase.cs

@@ -7,16 +7,24 @@ using System.Threading.Tasks;
 namespace HuntBuddy.Ipc;
 public abstract class ConsumerBase {
 	public const int MS_PER_AVAILABILITY_RECHECK = 5000;
+
+	public abstract string RequiredPlugin { get; }
+
 	private bool isAvailable;
 	private long timeSinceLastCheck;
 
 	public bool IsAvailable {
 		get {
 			if (Environment.TickCount64 > this.timeSinceLastCheck + MS_PER_AVAILABILITY_RECHECK) {
-				try {
-					this.isAvailable = this.Validate();
+				if (Service.PluginInterface.InstalledPlugins.Any(p => p.IsLoaded && p.InternalName == this.RequiredPlugin)) {
+					try {
+						this.isAvailable = this.Validate();
+					}
+					catch {
+						this.isAvailable = false;
+					}
 				}
-				catch {
+				else {
 					this.isAvailable = false;
 				}
 				this.timeSinceLastCheck = Environment.TickCount64;

+ 58 - 0
HuntBuddy/Ipc/EspConsumer.cs

@@ -0,0 +1,58 @@
+using System;
+
+using Dalamud.Plugin.Ipc;
+
+namespace HuntBuddy.Ipc;
+
+public class EspConsumer: ConsumerBase {
+	public override string RequiredPlugin { get; } = "XivEsp";
+	protected override bool Validate() {
+		this.getUnifiedSearch.InvokeFunc();
+		return true;
+	}
+
+	private ICallGateSubscriber<string> getUnifiedSearch = null!;
+	private ICallGateSubscriber<string, object> setSubstringSearch = null!;
+
+	private void Subscribe() {
+		try {
+			this.getUnifiedSearch = Service.PluginInterface.GetIpcSubscriber<string>("XivEsp.GetSearch");
+			this.setSubstringSearch = Service.PluginInterface.GetIpcSubscriber<string, object>("XivEsp.SetSubstring");
+		}
+		catch (Exception ex) {
+			Service.PluginLog.Debug($"Failed to subscribe to XivEsp\nReason: {ex}");
+		}
+	}
+
+	public EspConsumer() => this.Subscribe();
+
+	public bool CanSetSearch {
+		get {
+			try {
+				string current = this.getUnifiedSearch.InvokeFunc();
+				char type = current[0];
+				return type is 'N' or 'S';
+			}
+			catch {
+				return false;
+			}
+		}
+	}
+	public bool SearchFor(string target) {
+		try {
+			if (this.CanSetSearch) {
+				this.setSubstringSearch.InvokeAction(target);
+				return true;
+			}
+			else {
+				Service.Chat.Print("Cannot override complex (glob/regex) XivEsp search");
+				return false;
+			}
+		}
+		catch (Exception ex) {
+			Service.PluginLog.Error($"XivEsp is not responding to IPC: {ex}");
+			Service.Chat.PrintError("XivEsp plugin is not responding");
+			return false;
+		}
+	}
+}

+ 1 - 0
HuntBuddy/Ipc/TeleportConsumer.cs

@@ -5,6 +5,7 @@ using Dalamud.Plugin.Ipc;
 namespace HuntBuddy.Ipc;
 
 public class TeleportConsumer: ConsumerBase {
+	public override string RequiredPlugin { get; } = "TeleporterPlugin";
 	protected override bool Validate() {
 		this.consumerMessageSetting.InvokeFunc();
 		return true;

+ 20 - 17
HuntBuddy/Plugin.cs

@@ -1,9 +1,9 @@
 using System;
-using System.Numerics;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
+using System.Numerics;
 using System.Threading.Tasks;
 
 using Dalamud.Interface.Internal;
@@ -12,8 +12,6 @@ using Dalamud.Plugin;
 using Dalamud.Plugin.Services;
 using Dalamud.Utility;
 
-using Lumina.Excel.GeneratedSheets;
-
 using HuntBuddy.Attributes;
 using HuntBuddy.Ipc;
 using HuntBuddy.Structs;
@@ -23,6 +21,7 @@ using ImGuiNET;
 
 using Lumina.Data.Files;
 using Lumina.Excel;
+using Lumina.Excel.GeneratedSheets;
 using Lumina.Extensions;
 using Lumina.Text;
 
@@ -41,7 +40,8 @@ public class Plugin: IDalamudPlugin {
 	public bool MobHuntEntriesReady = true;
 	public readonly unsafe MobHuntStruct* MobHuntStruct;
 	public readonly Configuration Configuration;
-	public static TeleportConsumer? TeleportConsumer;
+	public static TeleportConsumer? TeleportConsumer { get; private set; }
+	public static EspConsumer? EspConsumer { get; private set; }
 
 	private WindowSystem WindowSystem {
 		get;
@@ -66,8 +66,8 @@ public class Plugin: IDalamudPlugin {
 		pluginInterface.Create<Service>();
 
 		this.commandManager = new PluginCommandManager<Plugin>(this, Service.Commands);
-		this.MobHuntEntries = new Dictionary<string, Dictionary<KeyValuePair<uint, string>, List<MobHuntEntry>>>();
-		this.CurrentAreaMobHuntEntries = new ConcurrentBag<MobHuntEntry>();
+		this.MobHuntEntries = [];
+		this.CurrentAreaMobHuntEntries = [];
 		this.Configuration = (Configuration)(Service.PluginInterface.GetPluginConfig() ?? new Configuration());
 		this.Configuration.IconBackgroundColourU32 =
 			ImGui.ColorConvertFloat4ToU32(this.Configuration.IconBackgroundColour);
@@ -87,6 +87,7 @@ public class Plugin: IDalamudPlugin {
 		this.WindowSystem.AddWindow(this.ConfigurationWindow);
 
 		Plugin.TeleportConsumer = new TeleportConsumer();
+		Plugin.EspConsumer = new EspConsumer();
 		Service.ClientState.TerritoryChanged += this.ClientStateOnTerritoryChanged;
 		Service.PluginInterface.UiBuilder.Draw += this.WindowSystem.Draw;
 		Service.PluginInterface.UiBuilder.OpenConfigUi += this.OpenConfigUi;
@@ -106,9 +107,9 @@ public class Plugin: IDalamudPlugin {
 		this.CurrentAreaMobHuntEntries.Clear();
 
 		foreach (MobHuntEntry mobHuntEntry in this.MobHuntEntries.SelectMany(
-			         expansionEntry => expansionEntry.Value
-				         .Where(entry => entry.Key.Key == Service.ClientState.TerritoryType)
-				         .SelectMany(entry => entry.Value))) {
+					 expansionEntry => expansionEntry.Value
+						 .Where(entry => entry.Key.Key == Service.ClientState.TerritoryType)
+						 .SelectMany(entry => entry.Value))) {
 			this.CurrentAreaMobHuntEntries.Add(mobHuntEntry);
 		}
 	}
@@ -149,7 +150,7 @@ public class Plugin: IDalamudPlugin {
 					break;
 				case "next":
 					if (this.MobHuntEntries.Count > 0) {
-						Func<MobHuntEntry, bool> filterPredicate = (MobHuntEntry entry) => entry.IsEliteMark ||
+						bool filterPredicate(MobHuntEntry entry) => entry.IsEliteMark ||
 							this.MobHuntStruct->CurrentKills[
 								entry.CurrentKillsOffset] <
 							entry.NeededKills;
@@ -181,7 +182,7 @@ public class Plugin: IDalamudPlugin {
 									.SelectMany(l => l)
 									.Where(filterPredicate)
 									.ToList()
-								: new List<MobHuntEntry>();
+								: [];
 							// if we didn't find any candidates, we try a different method to fill it
 							if (candidates.Count == 0) {
 								Service.PluginLog.Information(
@@ -209,7 +210,7 @@ public class Plugin: IDalamudPlugin {
 							}
 							else {
 								long remaining = chosen.NeededKills -
-								                 this.MobHuntStruct->CurrentKills[chosen.CurrentKillsOffset];
+												 this.MobHuntStruct->CurrentKills[chosen.CurrentKillsOffset];
 								Service.Chat.Print($"Hunting {remaining}x {chosen.Name} in {chosen.TerritoryName}");
 								Location.CreateMapMarker(
 									chosen.TerritoryType,
@@ -218,6 +219,8 @@ public class Plugin: IDalamudPlugin {
 									chosen.Name,
 									openType);
 							}
+							if (this.Configuration.EnableXivEspIntegration && this.Configuration.AutoSetEspSearchOnNextHuntCommand && Plugin.EspConsumer?.IsAvailable == true)
+								Plugin.EspConsumer.SearchFor(chosen.Name!);
 						}
 						else {
 							Service.PluginLog.Information("Unable to find a hunt mark to target");
@@ -253,7 +256,7 @@ public class Plugin: IDalamudPlugin {
 
 	public unsafe void ReloadData() {
 		this.MobHuntEntries.Clear();
-		List<MobHuntEntry> mobHuntList = new List<MobHuntEntry>();
+		List<MobHuntEntry> mobHuntList = [];
 		ExcelSheet<MobHuntOrder>? mobHuntOrderSheet = Service.DataManager.Excel.GetSheet<MobHuntOrder>()!;
 
 		foreach (BillEnum billNumber in Enum.GetValues<BillEnum>()) {
@@ -265,7 +268,7 @@ public class Plugin: IDalamudPlugin {
 				Service.DataManager.Excel.GetSheet<MobHuntOrderType>()!.GetRow((uint)billNumber)!;
 
 			uint rowId = mobHuntOrderTypeRow.OrderStart.Value!.RowId +
-			             (uint)(this.MobHuntStruct->BillOffset[mobHuntOrderTypeRow.RowId] - 1);
+						 (uint)(this.MobHuntStruct->BillOffset[mobHuntOrderTypeRow.RowId] - 1);
 
 			if (rowId > mobHuntOrderSheet.RowCount) {
 				continue;
@@ -309,14 +312,14 @@ public class Plugin: IDalamudPlugin {
 		foreach (MobHuntEntry entry in mobHuntList) {
 			string key = entry.ExpansionName ?? "Unknown";
 			KeyValuePair<uint, string> subKey =
-				new KeyValuePair<uint, string>(entry.TerritoryType, entry.TerritoryName ?? "Unknown");
+				new(entry.TerritoryType, entry.TerritoryName ?? "Unknown");
 
 			if (!this.MobHuntEntries.ContainsKey(key)) {
-				this.MobHuntEntries[key] = new Dictionary<KeyValuePair<uint, string>, List<MobHuntEntry>>();
+				this.MobHuntEntries[key] = [];
 			}
 
 			if (!this.MobHuntEntries[key].ContainsKey(subKey)) {
-				this.MobHuntEntries[key][subKey] = new List<MobHuntEntry>();
+				this.MobHuntEntries[key][subKey] = [];
 			}
 
 			this.MobHuntEntries[key][subKey].Add(entry);

+ 9 - 0
HuntBuddy/Windows/ConfigurationWindow.cs

@@ -32,6 +32,15 @@ public class ConfigurationWindow: Window {
 	public override void Draw() {
 		bool save = false;
 
+		ImGui.BeginDisabled(Plugin.EspConsumer?.IsAvailable == false);
+		save |= ImGui.Checkbox("Enable XivEsp plugin integration?", ref Plugin.Instance.Configuration.EnableXivEspIntegration);
+		ImGui.Indent();
+		save |= ImGui.Checkbox("Set XivEsp search when using '/phb next' command?", ref Plugin.Instance.Configuration.AutoSetEspSearchOnNextHuntCommand);
+		ImGui.Unindent();
+		ImGui.EndDisabled();
+
+		ImGui.Spacing();
+
 		save |= ImGui.Checkbox("Lock plugin window positions", ref Plugin.Instance.Configuration.LockWindowPositions);
 		save |= ImGui.Checkbox("Include hunt area on map by default",
 			ref Plugin.Instance.Configuration.IncludeAreaOnMap);

+ 19 - 7
HuntBuddy/Windows/LocalHuntsWindow.cs

@@ -14,7 +14,7 @@ namespace HuntBuddy.Windows;
 /// Local hunts window.
 /// </summary>
 public class LocalHuntsWindow: Window {
-	public LocalHuntsWindow(): base(
+	public LocalHuntsWindow() : base(
 		"Hunts in current area",
 		ImGuiWindowFlags.NoNavInputs | ImGuiWindowFlags.NoDocking,
 		true) {
@@ -46,12 +46,10 @@ public class LocalHuntsWindow: Window {
 		}
 	}
 
-	public override unsafe bool DrawConditions() =>
-		Plugin.Instance.Configuration.ShowLocalHunts &&
-		!Plugin.Instance.CurrentAreaMobHuntEntries.IsEmpty &&
-		Plugin.Instance.CurrentAreaMobHuntEntries.Count(
-			x => Plugin.Instance.MobHuntStruct->CurrentKills[x.CurrentKillsOffset] == x.NeededKills) !=
-		Plugin.Instance.CurrentAreaMobHuntEntries.Count;
+	public override unsafe bool DrawConditions() => Plugin.Instance.Configuration.ShowLocalHunts
+		&& !Plugin.Instance.CurrentAreaMobHuntEntries.IsEmpty
+		&& Plugin.Instance.CurrentAreaMobHuntEntries
+			.Count(x => Plugin.Instance.MobHuntStruct->CurrentKills[x.CurrentKillsOffset] == x.NeededKills) != Plugin.Instance.CurrentAreaMobHuntEntries.Count;
 
 	public override unsafe void Draw() {
 		foreach (MobHuntEntry? mobHuntEntry in Plugin.Instance.CurrentAreaMobHuntEntries) {
@@ -114,6 +112,20 @@ public class LocalHuntsWindow: Window {
 					ImGui.EndTooltip();
 				}
 
+				if (Plugin.Instance.Configuration.EnableXivEspIntegration && Plugin.EspConsumer?.IsAvailable == true) {
+
+					ImGui.SameLine();
+					if (InterfaceUtil.IconButton(FontAwesomeIcon.Search, $"esp##{mobHuntEntry.MobHuntId}")) {
+						Plugin.EspConsumer.SearchFor(mobHuntEntry.Name!);
+					}
+
+					if (ImGui.IsItemHovered()) {
+						ImGui.BeginTooltip();
+						ImGui.Text("Set XivEsp search to this target");
+						ImGui.EndTooltip();
+					}
+				}
+
 				ImGui.SameLine();
 			}
 

+ 38 - 28
HuntBuddy/Windows/MainWindow.cs

@@ -6,17 +6,17 @@ using System.Threading.Tasks;
 using Dalamud.Interface;
 using Dalamud.Interface.Windowing;
 
-using ImGuiNET;
-
 using HuntBuddy.Utils;
 
+using ImGuiNET;
+
 namespace HuntBuddy.Windows;
 
 /// <summary>
 /// Main plugin window.
 /// </summary>
 public class MainWindow: Window {
-	public MainWindow(): base(
+	public MainWindow() : base(
 		$"{Plugin.Instance.Name}",
 		ImGuiWindowFlags.NoDocking,
 		true) {
@@ -59,30 +59,26 @@ public class MainWindow: Window {
 			Plugin.Instance.OpenConfigUi();
 		}
 
-		foreach (KeyValuePair<string, Dictionary<KeyValuePair<uint, string>, List<MobHuntEntry>>> expansionEntry in
-		         Plugin.Instance.MobHuntEntries.Where(
-			         expansionEntry =>
-				         ImGui.TreeNode(expansionEntry.Key))) {
-			foreach (KeyValuePair<KeyValuePair<uint, string>, List<MobHuntEntry>> entry in expansionEntry.Value.Where(
-				         entry => {
-					         bool treeOpen = ImGui.TreeNodeEx(entry.Key.Value, ImGuiTreeNodeFlags.AllowItemOverlap);
-					         ImGui.SameLine();
-					         int killedCount = entry.Value.Count(
-						         x =>
-							         Plugin.Instance.MobHuntStruct->CurrentKills[x.CurrentKillsOffset] ==
-							         x.NeededKills);
-
-					         if (killedCount != entry.Value.Count) {
-						         ImGui.Text($"({killedCount}/{entry.Value.Count})");
-					         }
-					         else {
-						         ImGui.TextColored(
-							         new Vector4(0f, 1f, 0f, 1f),
-							         $"({killedCount}/{entry.Value.Count})");
-					         }
-
-					         return treeOpen;
-				         })) {
+		IEnumerable<KeyValuePair<string, Dictionary<KeyValuePair<uint, string>, List<MobHuntEntry>>>> expansionEntriesWithTreeNodes = Plugin.Instance
+			.MobHuntEntries
+			.Where(expansionEntry => ImGui.TreeNode(expansionEntry.Key));
+		foreach (KeyValuePair<string, Dictionary<KeyValuePair<uint, string>, List<MobHuntEntry>>> expansionEntry in expansionEntriesWithTreeNodes) {
+			IEnumerable<KeyValuePair<KeyValuePair<uint, string>, List<MobHuntEntry>>> mobEntriesWithTreeNodes = expansionEntry.Value
+				.Where(entry => {
+					bool treeOpen = ImGui.TreeNodeEx(entry.Key.Value, ImGuiTreeNodeFlags.AllowItemOverlap);
+					ImGui.SameLine();
+					int killedCount = entry.Value.Count(x => Plugin.Instance.MobHuntStruct->CurrentKills[x.CurrentKillsOffset] == x.NeededKills);
+					if (killedCount != entry.Value.Count) {
+						ImGui.Text($"({killedCount}/{entry.Value.Count})");
+					}
+					else {
+						ImGui.TextColored(
+							new Vector4(0f, 1f, 0f, 1f),
+							$"({killedCount}/{entry.Value.Count})");
+					}
+					return treeOpen;
+				});
+			foreach (KeyValuePair<KeyValuePair<uint, string>, List<MobHuntEntry>> entry in mobEntriesWithTreeNodes) {
 				foreach (MobHuntEntry? mobHuntEntry in entry.Value) {
 					if (Location.Database.ContainsKey(mobHuntEntry.MobHuntId)) {
 						if (InterfaceUtil.IconButton(FontAwesomeIcon.MapMarkerAlt, $"pin##{mobHuntEntry.MobHuntId}")) {
@@ -140,7 +136,7 @@ public class MainWindow: Window {
 						ImGui.SameLine();
 
 						if (Plugin.TeleportConsumer?.IsAvailable == true) {
-							if (InterfaceUtil.IconButton(FontAwesomeIcon.StreetView, $"t##{mobHuntEntry.MobHuntId}")) {
+							if (InterfaceUtil.IconButton(FontAwesomeIcon.StreetView, $"teleport##{mobHuntEntry.MobHuntId}")) {
 								Location.TeleportToNearestAetheryte(
 									mobHuntEntry.TerritoryType,
 									mobHuntEntry.MapId,
@@ -155,6 +151,20 @@ public class MainWindow: Window {
 
 							ImGui.SameLine();
 						}
+
+						if (Plugin.Instance.Configuration.EnableXivEspIntegration && Plugin.EspConsumer?.IsAvailable == true) {
+							if (InterfaceUtil.IconButton(FontAwesomeIcon.Search, $"esp##{mobHuntEntry.MobHuntId}")) {
+								Plugin.EspConsumer.SearchFor(mobHuntEntry.Name!);
+							}
+
+							if (ImGui.IsItemHovered()) {
+								ImGui.BeginTooltip();
+								ImGui.Text("Set XivEsp search to this target");
+								ImGui.EndTooltip();
+							}
+
+							ImGui.SameLine();
+						}
 					}
 
 					int currentKills = Plugin.Instance.MobHuntStruct->CurrentKills[mobHuntEntry.CurrentKillsOffset];