refactor: update for api 10

This commit is contained in:
Anna 2024-07-01 21:30:54 -04:00
parent cfdc84a4bb
commit 4c838b1ee5
Signed by: anna
GPG Key ID: D0943384CD9F87D1
8 changed files with 72 additions and 73 deletions

View File

@ -8,11 +8,11 @@ namespace PeepingTom.Ipc {
public const string FromRegistrationName = "PeepingTom.From";
public const string ToRegistrationName = "PeepingTom.To";
public static ICallGateProvider<IToMessage, object> GetProvider(DalamudPluginInterface @interface) {
public static ICallGateProvider<IToMessage, object> GetProvider(IDalamudPluginInterface @interface) {
return @interface.GetIpcProvider<IToMessage, object>(ToRegistrationName);
}
public static ICallGateSubscriber<IFromMessage, object> GetSubscriber(DalamudPluginInterface @interface) {
public static ICallGateSubscriber<IFromMessage, object> GetSubscriber(IDalamudPluginInterface @interface) {
return @interface.GetIpcSubscriber<IFromMessage, object>(FromRegistrationName);
}
}

View File

@ -10,27 +10,31 @@ namespace PeepingTom.Ipc {
public class Targeter {
[JsonConverter(typeof(SeStringConverter))]
public SeString Name { get; }
public uint HomeWorldId { get; }
public uint ObjectId { get; }
public ulong GameObjectId { get; }
public uint EntityId { get; }
public DateTime When { get; }
public Targeter(PlayerCharacter character) {
public Targeter(IPlayerCharacter character) {
this.Name = character.Name;
this.HomeWorldId = character.HomeWorld.Id;
this.ObjectId = character.ObjectId;
this.EntityId = character.EntityId;
this.GameObjectId = character.GameObjectId;
this.When = DateTime.UtcNow;
}
[JsonConstructor]
public Targeter(SeString name, uint homeWorldId, uint objectId, DateTime when) {
public Targeter(SeString name, uint homeWorldId, uint entityId, ulong gameObjectId, DateTime when) {
this.Name = name;
this.HomeWorldId = homeWorldId;
this.ObjectId = objectId;
this.EntityId = entityId;
this.GameObjectId = gameObjectId;
this.When = when;
}
public PlayerCharacter? GetPlayerCharacter(IObjectTable objectTable) {
return objectTable.FirstOrDefault(actor => actor.ObjectId == this.ObjectId && actor is PlayerCharacter) as PlayerCharacter;
public IPlayerCharacter? GetPlayerCharacter(IObjectTable objectTable) {
return objectTable.FirstOrDefault(actor => actor.GameObjectId == this.GameObjectId && actor is IPlayerCharacter) as IPlayerCharacter;
}
}
}

View File

@ -8,7 +8,7 @@ namespace PeepingTom {
internal class Configuration : IPluginConfiguration {
public int Version { get; set; } = 1;
private DalamudPluginInterface Interface { get; set; } = null!;
private IDalamudPluginInterface Interface { get; set; } = null!;
public bool MarkTargeted { get; set; }
@ -52,7 +52,7 @@ namespace PeepingTom {
public int PollFrequency { get; set; } = 100;
public void Initialize(DalamudPluginInterface pluginInterface) {
public void Initialize(IDalamudPluginInterface pluginInterface) {
this.Interface = pluginInterface;
}

View File

@ -37,6 +37,10 @@
<HintPath>$(DalamudLibPath)\ImGui.NET.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="FFXIVClientStructs">
<HintPath>$(DalamudLibPath)\FFXIVClientStructs.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Lumina">
<HintPath>$(DalamudLibPath)\Lumina.dll</HintPath>
<Private>False</Private>
@ -51,12 +55,11 @@
</Reference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="DalamudPackager" Version="2.1.12"/>
<PackageReference Include="Fody" Version="6.8.0" PrivateAssets="all"/>
<PackageReference Include="DalamudPackager" Version="2.1.13" />
<PackageReference Include="Fody" Version="6.8.1" PrivateAssets="all" />
<PackageReference Include="NAudio.Core" Version="2.2.1"/>
<PackageReference Include="NAudio.Wasapi" Version="2.2.1"/>
<PackageReference Include="Resourcer.Fody" Version="1.8.1" PrivateAssets="all"/>
<PackageReference Include="XivCommon" Version="9.0.0"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Peeping Tom.Ipc\Peeping Tom.Ipc.csproj"/>

View File

@ -7,7 +7,6 @@ using Dalamud.IoC;
using Dalamud.Plugin.Services;
using Lumina.Excel.GeneratedSheets;
using PeepingTom.Resources;
using XivCommon;
namespace PeepingTom {
// ReSharper disable once ClassNeverInstantiated.Global
@ -18,7 +17,7 @@ namespace PeepingTom {
internal static IPluginLog Log { get; private set; } = null!;
[PluginService]
internal DalamudPluginInterface Interface { get; init; } = null!;
internal IDalamudPluginInterface Interface { get; init; } = null!;
[PluginService]
internal IChatGui ChatGui { get; init; } = null!;
@ -53,13 +52,11 @@ namespace PeepingTom {
internal Configuration Config { get; }
internal PluginUi Ui { get; }
internal TargetWatcher Watcher { get; }
internal XivCommonBase Common { get; }
internal IpcManager IpcManager { get; }
internal bool InPvp { get; private set; }
public Plugin() {
this.Common = new XivCommonBase(this.Interface);
this.Config = this.Interface.GetPluginConfig() as Configuration ?? new Configuration();
this.Config.Initialize(this.Interface);
this.Watcher = new TargetWatcher(this);
@ -99,7 +96,6 @@ namespace PeepingTom {
this.IpcManager.Dispose();
this.Ui.Dispose();
this.Watcher.Dispose();
this.Common.Dispose();
}
private static void OnLanguageChange(string langCode) {

View File

@ -16,12 +16,13 @@ using PeepingTom.Ipc;
using PeepingTom.Resources;
using Dalamud.Interface.ImGuiFileDialog;
using Dalamud.Interface;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
namespace PeepingTom {
internal class PluginUi : IDisposable {
private Plugin Plugin { get; }
private uint? PreviousFocus { get; set; } = new();
private ulong? PreviousFocus { get; set; } = new();
private bool _wantsOpen;
@ -115,9 +116,9 @@ namespace PeepingTom {
}
var targeting = this.Plugin.Watcher.CurrentTargeters
.Select(targeter => this.Plugin.ObjectTable.FirstOrDefault(obj => obj.ObjectId == targeter.ObjectId))
.Where(targeter => targeter is PlayerCharacter)
.Cast<PlayerCharacter>()
.Select(targeter => this.Plugin.ObjectTable.FirstOrDefault(obj => obj.GameObjectId == targeter.GameObjectId))
.Where(targeter => targeter is IPlayerCharacter)
.Cast<IPlayerCharacter>()
.ToArray();
foreach (var targeter in targeting) {
this.MarkPlayer(targeter, this.Plugin.Config.TargetingColour, this.Plugin.Config.TargetingSize);
@ -408,15 +409,15 @@ namespace PeepingTom {
// to prevent looping over a subset of the actors repeatedly when multiple people are targeting,
// create a dictionary for O(1) lookups by actor id
Dictionary<uint, GameObject>? objects = null;
Dictionary<ulong, IGameObject>? objects = null;
if (targeting.Count + (previousTargeters?.Count ?? 0) > 1) {
var dict = new Dictionary<uint, GameObject>();
var dict = new Dictionary<ulong, IGameObject>();
foreach (var obj in this.Plugin.ObjectTable) {
if (dict.ContainsKey(obj.ObjectId) || obj.ObjectKind != ObjectKind.Player) {
if (dict.ContainsKey(obj.GameObjectId) || obj.ObjectKind != ObjectKind.Player) {
continue;
}
dict.Add(obj.ObjectId, obj);
dict.Add(obj.GameObjectId, obj);
}
objects = dict;
@ -459,20 +460,20 @@ namespace PeepingTom {
// }
foreach (var targeter in targeting) {
GameObject? obj = null;
objects?.TryGetValue(targeter.ObjectId, out obj);
IGameObject? obj = null;
objects?.TryGetValue(targeter.GameObjectId, out obj);
this.AddEntry(targeter, obj, ref anyHovered);
}
if (this.Plugin.Config.KeepHistory) {
// get a list of the previous targeters that aren't currently targeting
var previous = (previousTargeters ?? new List<Targeter>())
.Where(old => targeting.All(actor => actor.ObjectId != old.ObjectId))
.Where(old => targeting.All(actor => actor.GameObjectId != old.GameObjectId))
.Take(this.Plugin.Config.NumHistory);
// add previous targeters to the list
foreach (var oldTargeter in previous) {
GameObject? obj = null;
objects?.TryGetValue(oldTargeter.ObjectId, out obj);
IGameObject? obj = null;
objects?.TryGetValue(oldTargeter.GameObjectId, out obj);
this.AddEntry(oldTargeter, obj, ref anyHovered, ImGuiSelectableFlags.Disabled);
}
}
@ -485,7 +486,7 @@ namespace PeepingTom {
if (previousFocus == uint.MaxValue) {
this.Plugin.TargetManager.FocusTarget = null;
} else {
var actor = this.Plugin.ObjectTable.FirstOrDefault(a => a.ObjectId == previousFocus);
var actor = this.Plugin.ObjectTable.FirstOrDefault(a => a.GameObjectId == previousFocus);
// either target the actor if still present or target nothing
this.Plugin.TargetManager.FocusTarget = actor;
}
@ -510,7 +511,7 @@ namespace PeepingTom {
ImGui.EndTooltip();
}
private void AddEntry(Targeter targeter, GameObject? obj, ref bool anyHovered, ImGuiSelectableFlags flags = ImGuiSelectableFlags.None) {
private void AddEntry(Targeter targeter, IGameObject? obj, ref bool anyHovered, ImGuiSelectableFlags flags = ImGuiSelectableFlags.None) {
ImGui.BeginGroup();
ImGui.Selectable(targeter.Name.TextValue, false, flags);
@ -539,7 +540,7 @@ namespace PeepingTom {
var left = hover && ImGui.IsMouseClicked(ImGuiMouseButton.Left);
var right = hover && ImGui.IsMouseClicked(ImGuiMouseButton.Right);
obj ??= this.Plugin.ObjectTable.FirstOrDefault(a => a.ObjectId == targeter.ObjectId);
obj ??= this.Plugin.ObjectTable.FirstOrDefault(a => a.GameObjectId == targeter.GameObjectId);
// don't count as hovered if the actor isn't here (clears focus target when hovering missing actors)
if (obj != null) {
@ -547,21 +548,23 @@ namespace PeepingTom {
}
if (this.Plugin.Config.FocusTargetOnHover && hover && obj != null) {
this.PreviousFocus ??= this.Plugin.TargetManager.FocusTarget?.ObjectId ?? uint.MaxValue;
this.PreviousFocus ??= this.Plugin.TargetManager.FocusTarget?.GameObjectId ?? uint.MaxValue;
this.Plugin.TargetManager.FocusTarget = obj;
}
if (left) {
if (this.Plugin.Config.OpenExamine && ImGui.GetIO().KeyAlt) {
if (obj != null) {
this.Plugin.Common.Functions.Examine.OpenExamineWindow(obj);
unsafe {
AgentInspect.Instance()->ExamineCharacter(obj.EntityId);
}
} else {
var error = string.Format(Language.ExamineErrorToast, targeter.Name);
this.Plugin.ToastGui.ShowError(error);
}
} else {
var payload = new PlayerPayload(targeter.Name.TextValue, targeter.HomeWorldId);
Payload[] payloads = { payload };
Payload[] payloads = [payload];
this.Plugin.ChatGui.Print(new XivChatEntry {
Message = new SeString(payloads),
});
@ -571,7 +574,7 @@ namespace PeepingTom {
}
}
private void MarkPlayer(GameObject? player, Vector4 colour, float size) {
private void MarkPlayer(IGameObject? player, Vector4 colour, float size) {
if (player == null) {
return;
}
@ -592,7 +595,7 @@ namespace PeepingTom {
ImGui.PopClipRect();
}
private PlayerCharacter? GetCurrentTarget() {
private IPlayerCharacter? GetCurrentTarget() {
var player = this.Plugin.ClientState.LocalPlayer;
if (player == null) {
return null;
@ -604,8 +607,8 @@ namespace PeepingTom {
}
return this.Plugin.ObjectTable
.Where(actor => actor.ObjectId == targetId && actor is PlayerCharacter)
.Select(actor => actor as PlayerCharacter)
.Where(actor => actor.GameObjectId == targetId && actor is IPlayerCharacter)
.Select(actor => actor as IPlayerCharacter)
.FirstOrDefault();
}
}

View File

@ -21,11 +21,11 @@ namespace PeepingTom {
private Stopwatch? SoundWatch { get; set; }
private int LastTargetAmount { get; set; }
private Targeter[] Current { get; set; } = Array.Empty<Targeter>();
private Targeter[] Current { get; set; } = [];
public IReadOnlyCollection<Targeter> CurrentTargeters => this.Current;
private List<Targeter> Previous { get; } = new();
private List<Targeter> Previous { get; } = [];
public IReadOnlyCollection<Targeter> PreviousTargeters => this.Previous;
@ -63,7 +63,7 @@ namespace PeepingTom {
// get targeters and set a copy so we can release the mutex faster
var newCurrent = this.GetTargeting(this.Plugin.ObjectTable, player);
foreach (var newTargeter in newCurrent.Where(t => this.Current.All(c => c.ObjectId != t.ObjectId))) {
foreach (var newTargeter in newCurrent.Where(t => this.Current.All(c => c.GameObjectId != t.GameObjectId))) {
try {
this.Plugin.IpcManager.SendNewTargeter(newTargeter);
} catch (Exception ex) {
@ -71,7 +71,7 @@ namespace PeepingTom {
}
}
foreach (var stopped in this.Current.Where(t => newCurrent.All(c => c.ObjectId != t.ObjectId))) {
foreach (var stopped in this.Current.Where(t => newCurrent.All(c => c.GameObjectId != t.GameObjectId))) {
try {
this.Plugin.IpcManager.SendStoppedTargeting(stopped);
} catch (Exception ex) {
@ -99,42 +99,42 @@ namespace PeepingTom {
foreach (var targeter in targeting) {
// add the targeter to the previous list
if (this.Previous.Any(old => old.ObjectId == targeter.ObjectId)) {
this.Previous.RemoveAll(old => old.ObjectId == targeter.ObjectId);
if (this.Previous.Any(old => old.GameObjectId == targeter.GameObjectId)) {
this.Previous.RemoveAll(old => old.GameObjectId == targeter.GameObjectId);
}
this.Previous.Insert(0, targeter);
}
// only keep the configured number of previous targeters (ignoring ones that are currently targeting)
while (this.Previous.Count(old => targeting.All(actor => actor.ObjectId != old.ObjectId)) > this.Plugin.Config.NumHistory) {
while (this.Previous.Count(old => targeting.All(actor => actor.GameObjectId != old.GameObjectId)) > this.Plugin.Config.NumHistory) {
this.Previous.RemoveAt(this.Previous.Count - 1);
}
}
private Targeter[] GetTargeting(IEnumerable<GameObject> objects, GameObject player) {
private Targeter[] GetTargeting(IEnumerable<IGameObject> objects, IGameObject player) {
return objects
.Where(obj => obj.TargetObjectId == player.ObjectId && obj is PlayerCharacter)
.Where(obj => obj.TargetObjectId == player.GameObjectId && obj is IPlayerCharacter)
// .Where(obj => Marshal.ReadByte(obj.Address + ActorOffsets.PlayerCharacterTargetActorId + 4) == 0)
.Cast<PlayerCharacter>()
.Cast<IPlayerCharacter>()
.Where(actor => this.Plugin.Config.LogParty || !InParty(actor))
.Where(actor => this.Plugin.Config.LogAlliance || !InAlliance(actor))
.Where(actor => this.Plugin.Config.LogInCombat || !InCombat(actor))
.Where(actor => this.Plugin.Config.LogSelf || actor.ObjectId != player.ObjectId)
.Where(actor => this.Plugin.Config.LogSelf || actor.GameObjectId != player.GameObjectId)
.Select(actor => new Targeter(actor))
.ToArray();
}
private static byte GetStatus(GameObject actor) {
private static byte GetStatus(IGameObject actor) {
var statusPtr = actor.Address + 0x1980; // updated 5.4
return Marshal.ReadByte(statusPtr);
}
private static bool InCombat(GameObject actor) => (GetStatus(actor) & 2) > 0;
private static bool InCombat(IGameObject actor) => (GetStatus(actor) & 2) > 0;
private static bool InParty(GameObject actor) => (GetStatus(actor) & 16) > 0;
private static bool InParty(IGameObject actor) => (GetStatus(actor) & 16) > 0;
private static bool InAlliance(GameObject actor) => (GetStatus(actor) & 32) > 0;
private static bool InAlliance(IGameObject actor) => (GetStatus(actor) & 32) > 0;
private bool CanPlaySound() {
if (!this.Plugin.Config.PlaySoundOnTarget) {
@ -178,10 +178,9 @@ namespace PeepingTom {
return;
}
using var channel = new WaveChannel32(reader) {
Volume = this.Plugin.Config.SoundVolume,
PadWithZeroes = false,
};
using var channel = new WaveChannel32(reader);
channel.Volume = this.Plugin.Config.SoundVolume;
channel.PadWithZeroes = false;
using (reader) {
using var output = new DirectSoundOut(soundDevice.Guid);

18
Peeping Tom/packages.lock.json Normal file → Executable file
View File

@ -4,15 +4,15 @@
"net8.0-windows7.0": {
"DalamudPackager": {
"type": "Direct",
"requested": "[2.1.12, )",
"resolved": "2.1.12",
"contentHash": "Sc0PVxvgg4NQjcI8n10/VfUQBAS4O+Fw2pZrAqBdRMbthYGeogzu5+xmIGCGmsEZ/ukMOBuAqiNiB5qA3MRalg=="
"requested": "[2.1.13, )",
"resolved": "2.1.13",
"contentHash": "rMN1omGe8536f4xLMvx9NwfvpAc9YFFfeXJ1t4P4PE6Gu8WCIoFliR1sh07hM+bfODmesk/dvMbji7vNI+B/pQ=="
},
"Fody": {
"type": "Direct",
"requested": "[6.8.0, )",
"resolved": "6.8.0",
"contentHash": "hfZ/f8Mezt8aTkgv9nsvFdYoQ809/AqwsJlOGOPYIfBcG2aAIG3v3ex9d8ZqQuFYyMoucjRg4eKy3VleeGodKQ=="
"requested": "[6.8.1, )",
"resolved": "6.8.1",
"contentHash": "pwk2/No1kL1ft+zMT2y0MvzB6W5cpkdOTj+0+T2u7LGJMTw37qtlnHzCSCyvwRiZVoJ/V/DE78eQ/WEcutUVDw=="
},
"NAudio.Core": {
"type": "Direct",
@ -38,12 +38,6 @@
"Fody": "6.6.4"
}
},
"XivCommon": {
"type": "Direct",
"requested": "[9.0.0, )",
"resolved": "9.0.0",
"contentHash": "avaBp3FmSCi/PiQhntCeBDYOHejdyTWmFtz4pRBVQQ8vHkmRx+YTk1la9dkYBMlXxRXKckEdH1iI1Fu61JlE7w=="
},
"PeepingTom.Ipc": {
"type": "Project"
}