refactor: move to net5
This commit is contained in:
parent
b451db08f6
commit
15a1674ed2
|
@ -1,2 +1,3 @@
|
|||
* text eol=lf
|
||||
*.wav binary
|
||||
*.png binary
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PeepingTom.Ipc.From {
|
||||
[Serializable]
|
||||
public class AllTargetersMessage : IFromMessage {
|
||||
public List<(Targeter targeter, bool currentlyTargeting)> Targeters { get; }
|
||||
|
||||
public AllTargetersMessage(List<(Targeter, bool)> targeters) {
|
||||
this.Targeters = targeters;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
namespace PeepingTom.Ipc.From {
|
||||
public interface IFromMessage {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace PeepingTom.Ipc.From {
|
||||
[Serializable]
|
||||
public class NewTargeterMessage : IFromMessage {
|
||||
public Targeter Targeter { get; }
|
||||
|
||||
public NewTargeterMessage(Targeter targeter) {
|
||||
this.Targeter = targeter;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace PeepingTom.Ipc.From {
|
||||
[Serializable]
|
||||
public class StoppedTargetingMessage : IFromMessage {
|
||||
public Targeter Targeter { get; }
|
||||
|
||||
public StoppedTargetingMessage(Targeter targeter) {
|
||||
this.Targeter = targeter;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using Dalamud.Plugin;
|
||||
using PeepingTom.Ipc.From;
|
||||
using PeepingTom.Ipc.To;
|
||||
|
||||
namespace PeepingTom.Ipc {
|
||||
public static class IpcInfo {
|
||||
public const string FromRegistrationName = "PeepingTom.From";
|
||||
public const string ToRegistrationName = "PeepingTom.To";
|
||||
|
||||
public static ICallGateProvider<IToMessage, object> GetProvider(DalamudPluginInterface @interface) {
|
||||
return @interface.GetIpcProvider<IToMessage, object>(ToRegistrationName);
|
||||
}
|
||||
|
||||
public static ICallGateSubscriber<IFromMessage, object> GetSubscriber(DalamudPluginInterface @interface) {
|
||||
return @interface.GetIpcSubscriber<IFromMessage, object>(FromRegistrationName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<Version>1.0.0</Version>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>PeepingTom.Ipc</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Dalamud">
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Dalamud.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Lumina.Excel">
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Lumina.Excel.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
|
||||
namespace PeepingTom.Ipc {
|
||||
[Serializable]
|
||||
public class Targeter {
|
||||
public SeString Name { get; }
|
||||
public uint HomeWorldId { get; }
|
||||
public uint ObjectId { get; }
|
||||
public DateTime When { get; }
|
||||
|
||||
public Targeter(PlayerCharacter character) {
|
||||
this.Name = character.Name;
|
||||
this.HomeWorldId = character.HomeWorld.Id;
|
||||
this.ObjectId = character.ObjectId;
|
||||
this.When = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public PlayerCharacter? GetPlayerCharacter(ObjectTable objectTable) {
|
||||
return objectTable.FirstOrDefault(actor => actor.ObjectId == this.ObjectId && actor is PlayerCharacter) as PlayerCharacter;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
namespace PeepingTom.Ipc.To {
|
||||
public interface IToMessage {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
using System;
|
||||
|
||||
namespace PeepingTom.Ipc.To {
|
||||
[Serializable]
|
||||
public class RequestTargetersMessage : IToMessage {
|
||||
}
|
||||
}
|
|
@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Peeping Tom", "Peeping Tom\
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9B879446-A687-4B9D-8628-807CCB8C51AE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Peeping Tom.Ipc", "Peeping Tom.Ipc\Peeping Tom.Ipc.csproj", "{F454FB15-2C11-44F3-A651-E5F912F0FE11}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -17,6 +19,10 @@ Global
|
|||
{888F98DF-AF1D-4852-8411-11B1FEEFE674}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{888F98DF-AF1D-4852-8411-11B1FEEFE674}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{888F98DF-AF1D-4852-8411-11B1FEEFE674}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F454FB15-2C11-44F3-A651-E5F912F0FE11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F454FB15-2C11-44F3-A651-E5F912F0FE11}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F454FB15-2C11-44F3-A651-E5F912F0FE11}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F454FB15-2C11-44F3-A651-E5F912F0FE11}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
OutputPath="$(OutputPath)"
|
||||
AssemblyName="$(AssemblyName)"
|
||||
VersionComponents="3"
|
||||
Include="PeepingTom.dll;PeepingTom.json;PeepingTom.pdb"
|
||||
MakeZip="true"/>
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<Resourcer/>
|
||||
<ResourcesMerge/>
|
||||
<ILMerge ExcludeResources="^NAudio\.WinForms\..+"/>
|
||||
</Weavers>
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Plugin;
|
||||
using PeepingTom.Ipc;
|
||||
using PeepingTom.Ipc.From;
|
||||
using PeepingTom.Ipc.To;
|
||||
|
||||
namespace PeepingTom {
|
||||
internal class IpcManager : IDisposable {
|
||||
private PeepingTomPlugin Plugin { get; }
|
||||
|
||||
private ICallGateProvider<IFromMessage, object> Provider { get; }
|
||||
private ICallGateSubscriber<IToMessage, object> Subscriber { get; }
|
||||
|
||||
internal IpcManager(PeepingTomPlugin plugin) {
|
||||
this.Plugin = plugin;
|
||||
|
||||
this.Provider = this.Plugin.Interface.GetIpcProvider<IFromMessage, object>(IpcInfo.FromRegistrationName);
|
||||
this.Subscriber = this.Plugin.Interface.GetIpcSubscriber<IToMessage, object>(IpcInfo.ToRegistrationName);
|
||||
|
||||
this.Subscriber.Subscribe(this.ReceiveMessage);
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
this.Subscriber.Unsubscribe(this.ReceiveMessage);
|
||||
}
|
||||
|
||||
internal void SendAllTargeters() {
|
||||
var targeters = new List<(Targeter, bool)>();
|
||||
targeters.AddRange(this.Plugin.Watcher.CurrentTargeters.Select(t => (t, true)));
|
||||
targeters.AddRange(this.Plugin.Watcher.PreviousTargeters.Select(t => (t, false)));
|
||||
|
||||
this.Provider.SendMessage(new AllTargetersMessage(targeters));
|
||||
}
|
||||
|
||||
internal void SendNewTargeter(Targeter targeter) {
|
||||
this.Provider.SendMessage(new NewTargeterMessage(targeter));
|
||||
}
|
||||
|
||||
internal void SendStoppedTargeting(Targeter targeter) {
|
||||
this.Provider.SendMessage(new StoppedTargetingMessage(targeter));
|
||||
}
|
||||
|
||||
private void ReceiveMessage(IToMessage message) {
|
||||
switch (message) {
|
||||
case RequestTargetersMessage: {
|
||||
this.SendAllTargeters();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<TargetFramework>net5-windows</TargetFramework>
|
||||
<RootNamespace>PeepingTom</RootNamespace>
|
||||
<Version>1.7.5</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<AssemblyName>PeepingTom</AssemblyName>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\target.wav"/>
|
||||
|
@ -37,19 +39,16 @@
|
|||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Lumina.Excel.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="SharpDX.Mathematics">
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\SharpDX.Mathematics.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DalamudPackager" Version="1.2.1"/>
|
||||
<PackageReference Include="Fody" Version="6.5.1" PrivateAssets="all"/>
|
||||
<PackageReference Include="ILMerge.Fody" Version="1.16.0" PrivateAssets="all"/>
|
||||
<PackageReference Include="NAudio" Version="2.0.0"/>
|
||||
<PackageReference Include="DalamudPackager" Version="2.1.2"/>
|
||||
<PackageReference Include="Fody" Version="6.5.2" PrivateAssets="all"/>
|
||||
<PackageReference Include="NAudio" Version="2.0.1"/>
|
||||
<PackageReference Include="Resourcer.Fody" Version="1.8.0" PrivateAssets="all"/>
|
||||
<PackageReference Include="ResourcesMerge.Fody" Version="1.0.1" PrivateAssets="all"/>
|
||||
<PackageReference Include="XivCommon" Version="1.5.0"/>
|
||||
<PackageReference Include="XivCommon" Version="3.0.1"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Peeping Tom.Ipc\Peeping Tom.Ipc.csproj"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="Resources\Language.Designer.cs">
|
||||
|
@ -58,4 +57,7 @@
|
|||
<DependentUpon>Language.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="..\icon.png" Link="images/icon.png" CopyToOutputDirectory="PreserveNewest" Visible="false"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
author: ascclemens
|
||||
name: Peeping Tom
|
||||
punchline: Shows who is currently or was previously targeting you.
|
||||
description: Shows who is currently or was previously targeting you.
|
||||
repo_url: https://sr.ht/~jkcclemens/PeepingTom
|
||||
|
|
|
@ -3,78 +3,117 @@ using Dalamud.Plugin;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.Gui;
|
||||
using Dalamud.Game.Gui.Toast;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.Logging;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using PeepingTom.Resources;
|
||||
using XivCommon;
|
||||
using Condition = Dalamud.Game.ClientState.Conditions.Condition;
|
||||
|
||||
namespace PeepingTom {
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
public class PeepingTomPlugin : IDalamudPlugin {
|
||||
public string Name => "Peeping Tom";
|
||||
|
||||
internal DalamudPluginInterface Interface { get; private set; } = null!;
|
||||
internal Configuration Config { get; private set; } = null!;
|
||||
internal PluginUi Ui { get; private set; } = null!;
|
||||
internal TargetWatcher Watcher { get; private set; } = null!;
|
||||
internal XivCommonBase Common { get; private set; } = null!;
|
||||
[PluginService]
|
||||
internal DalamudPluginInterface Interface { get; init; } = null!;
|
||||
|
||||
[PluginService]
|
||||
internal ChatGui ChatGui { get; init; } = null!;
|
||||
|
||||
[PluginService]
|
||||
internal ClientState ClientState { get; init; } = null!;
|
||||
|
||||
[PluginService]
|
||||
private CommandManager CommandManager { get; init; } = null!;
|
||||
|
||||
[PluginService]
|
||||
internal Condition Condition { get; init; } = null!;
|
||||
|
||||
[PluginService]
|
||||
internal DataManager DataManager { get; init; } = null!;
|
||||
|
||||
[PluginService]
|
||||
internal Framework Framework { get; init; } = null!;
|
||||
|
||||
[PluginService]
|
||||
internal GameGui GameGui { get; init; } = null!;
|
||||
|
||||
[PluginService]
|
||||
internal ObjectTable ObjectTable { get; init; } = null!;
|
||||
|
||||
[PluginService]
|
||||
internal TargetManager TargetManager { get; init; } = null!;
|
||||
|
||||
[PluginService]
|
||||
internal ToastGui ToastGui { get; init; } = null!;
|
||||
|
||||
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 void Initialize(DalamudPluginInterface pluginInterface) {
|
||||
this.Interface = pluginInterface;
|
||||
this.Common = new XivCommonBase(this.Interface);
|
||||
public PeepingTomPlugin() {
|
||||
this.Common = new XivCommonBase();
|
||||
this.Config = this.Interface.GetPluginConfig() as Configuration ?? new Configuration();
|
||||
this.Config.Initialize(this.Interface);
|
||||
this.Watcher = new TargetWatcher(this);
|
||||
this.Ui = new PluginUi(this);
|
||||
this.IpcManager = new IpcManager(this);
|
||||
|
||||
OnLanguageChange(this.Interface.UiLanguage);
|
||||
this.Interface.OnLanguageChanged += OnLanguageChange;
|
||||
this.Interface.LanguageChanged += OnLanguageChange;
|
||||
|
||||
this.Interface.CommandManager.AddHandler("/ppeepingtom", new CommandInfo(this.OnCommand) {
|
||||
this.CommandManager.AddHandler("/ppeepingtom", new CommandInfo(this.OnCommand) {
|
||||
HelpMessage = "Use with no arguments to show the list. Use with \"c\" or \"config\" to show the config",
|
||||
});
|
||||
this.Interface.CommandManager.AddHandler("/ptom", new CommandInfo(this.OnCommand) {
|
||||
this.CommandManager.AddHandler("/ptom", new CommandInfo(this.OnCommand) {
|
||||
HelpMessage = "Alias for /ppeepingtom",
|
||||
});
|
||||
this.Interface.CommandManager.AddHandler("/ppeep", new CommandInfo(this.OnCommand) {
|
||||
this.CommandManager.AddHandler("/ppeep", new CommandInfo(this.OnCommand) {
|
||||
HelpMessage = "Alias for /ppeepingtom",
|
||||
});
|
||||
|
||||
this.Interface.Framework.OnUpdateEvent += this.Watcher.OnFrameworkUpdate;
|
||||
this.Interface.ClientState.OnLogin += this.OnLogin;
|
||||
this.Interface.ClientState.OnLogout += this.OnLogout;
|
||||
this.Interface.ClientState.TerritoryChanged += this.OnTerritoryChange;
|
||||
this.Interface.UiBuilder.OnBuildUi += this.DrawUi;
|
||||
this.Interface.UiBuilder.OnOpenConfigUi += this.ConfigUi;
|
||||
|
||||
this.Watcher.StartThread();
|
||||
this.ClientState.Login += this.OnLogin;
|
||||
this.ClientState.Logout += this.OnLogout;
|
||||
this.ClientState.TerritoryChanged += this.OnTerritoryChange;
|
||||
this.Interface.UiBuilder.Draw += this.DrawUi;
|
||||
this.Interface.UiBuilder.OpenConfigUi += this.ConfigUi;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
this.Common.Dispose();
|
||||
this.Interface.Framework.OnUpdateEvent -= this.Watcher.OnFrameworkUpdate;
|
||||
this.Interface.ClientState.OnLogin -= this.OnLogin;
|
||||
this.Interface.ClientState.OnLogout -= this.OnLogout;
|
||||
this.Watcher.WaitStopThread();
|
||||
this.Watcher.Dispose();
|
||||
this.Interface.UiBuilder.OnBuildUi -= this.DrawUi;
|
||||
this.Interface.UiBuilder.OnOpenConfigUi -= this.ConfigUi;
|
||||
this.Interface.CommandManager.RemoveHandler("/ppeepingtom");
|
||||
this.Interface.CommandManager.RemoveHandler("/ptom");
|
||||
this.Interface.CommandManager.RemoveHandler("/ppeep");
|
||||
this.Interface.UiBuilder.OpenConfigUi -= this.ConfigUi;
|
||||
this.Interface.UiBuilder.Draw -= this.DrawUi;
|
||||
this.ClientState.TerritoryChanged -= this.OnTerritoryChange;
|
||||
this.ClientState.Logout -= this.OnLogout;
|
||||
this.ClientState.Login -= this.OnLogin;
|
||||
this.CommandManager.RemoveHandler("/ppeep");
|
||||
this.CommandManager.RemoveHandler("/ptom");
|
||||
this.CommandManager.RemoveHandler("/ppeepingtom");
|
||||
this.Interface.LanguageChanged -= OnLanguageChange;
|
||||
this.IpcManager.Dispose();
|
||||
this.Ui.Dispose();
|
||||
this.Interface.OnLanguageChanged -= OnLanguageChange;
|
||||
this.Watcher.Dispose();
|
||||
this.Common.Dispose();
|
||||
}
|
||||
|
||||
private static void OnLanguageChange(string langCode) {
|
||||
Language.Culture = new CultureInfo(langCode);
|
||||
}
|
||||
|
||||
private void OnTerritoryChange(object sender, ushort e) {
|
||||
private void OnTerritoryChange(object? sender, ushort e) {
|
||||
try {
|
||||
var territory = this.Interface.Data.GetExcelSheet<TerritoryType>().GetRow(e);
|
||||
this.InPvp = territory.IsPvpZone;
|
||||
var territory = this.DataManager.GetExcelSheet<TerritoryType>()!.GetRow(e);
|
||||
this.InPvp = territory?.IsPvpZone == true;
|
||||
} catch (KeyNotFoundException) {
|
||||
PluginLog.Warning("Could not get territory for current zone");
|
||||
}
|
||||
|
@ -88,7 +127,7 @@ namespace PeepingTom {
|
|||
}
|
||||
}
|
||||
|
||||
private void OnLogin(object sender, EventArgs args) {
|
||||
private void OnLogin(object? sender, EventArgs args) {
|
||||
if (!this.Config.OpenOnLogin) {
|
||||
return;
|
||||
}
|
||||
|
@ -96,7 +135,7 @@ namespace PeepingTom {
|
|||
this.Ui.WantsOpen = true;
|
||||
}
|
||||
|
||||
private void OnLogout(object sender, EventArgs args) {
|
||||
private void OnLogout(object? sender, EventArgs args) {
|
||||
this.Ui.WantsOpen = false;
|
||||
this.Watcher.ClearPrevious();
|
||||
}
|
||||
|
@ -105,7 +144,7 @@ namespace PeepingTom {
|
|||
this.Ui.Draw();
|
||||
}
|
||||
|
||||
private void ConfigUi(object sender, EventArgs args) {
|
||||
private void ConfigUi() {
|
||||
this.Ui.SettingsOpen = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,25 @@
|
|||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.ClientState.Actors.Types;
|
||||
using ImGuiNET;
|
||||
using ImGuiNET;
|
||||
using NAudio.Wave;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.Text;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using Dalamud.Interface;
|
||||
using PeepingTom.Ipc;
|
||||
using PeepingTom.Resources;
|
||||
|
||||
namespace PeepingTom {
|
||||
internal class PluginUi : IDisposable {
|
||||
private PeepingTomPlugin Plugin { get; }
|
||||
|
||||
private Optional<Actor> PreviousFocus { get; set; } = new();
|
||||
private uint? PreviousFocus { get; set; } = new();
|
||||
|
||||
private bool _wantsOpen;
|
||||
|
||||
|
@ -52,13 +55,13 @@ namespace PeepingTom {
|
|||
this.ShowSettings();
|
||||
}
|
||||
|
||||
var inCombat = this.Plugin.Interface.ClientState.Condition[ConditionFlag.InCombat];
|
||||
var inInstance = this.Plugin.Interface.ClientState.Condition[ConditionFlag.BoundByDuty]
|
||||
|| this.Plugin.Interface.ClientState.Condition[ConditionFlag.BoundByDuty56]
|
||||
|| this.Plugin.Interface.ClientState.Condition[ConditionFlag.BoundByDuty95];
|
||||
var inCutscene = this.Plugin.Interface.ClientState.Condition[ConditionFlag.WatchingCutscene]
|
||||
|| this.Plugin.Interface.ClientState.Condition[ConditionFlag.WatchingCutscene78]
|
||||
|| this.Plugin.Interface.ClientState.Condition[ConditionFlag.OccupiedInCutSceneEvent];
|
||||
var inCombat = this.Plugin.Condition[ConditionFlag.InCombat];
|
||||
var inInstance = this.Plugin.Condition[ConditionFlag.BoundByDuty]
|
||||
|| this.Plugin.Condition[ConditionFlag.BoundByDuty56]
|
||||
|| this.Plugin.Condition[ConditionFlag.BoundByDuty95];
|
||||
var inCutscene = this.Plugin.Condition[ConditionFlag.WatchingCutscene]
|
||||
|| this.Plugin.Condition[ConditionFlag.WatchingCutscene78]
|
||||
|| this.Plugin.Condition[ConditionFlag.OccupiedInCutSceneEvent];
|
||||
|
||||
// FIXME: this could just be a boolean expression
|
||||
var shouldBeShown = this.WantsOpen;
|
||||
|
@ -101,13 +104,13 @@ namespace PeepingTom {
|
|||
goto EndDummy;
|
||||
}
|
||||
|
||||
var player = this.Plugin.Interface.ClientState.LocalPlayer;
|
||||
var player = this.Plugin.ClientState.LocalPlayer;
|
||||
if (player == null) {
|
||||
goto EndDummy;
|
||||
}
|
||||
|
||||
var targeting = this.Plugin.Watcher.CurrentTargeters
|
||||
.Select(targeter => this.Plugin.Interface.ClientState.Actors.FirstOrDefault(actor => actor.ActorId == targeter.ActorId))
|
||||
.Select(targeter => this.Plugin.ObjectTable.FirstOrDefault(obj => obj.ObjectId == targeter.ObjectId))
|
||||
.Where(targeter => targeter is PlayerCharacter)
|
||||
.Cast<PlayerCharacter>()
|
||||
.ToArray();
|
||||
|
@ -377,10 +380,10 @@ namespace PeepingTom {
|
|||
.Where(actor => actor.TargetActorID == player.ActorId && actor is PlayerCharacter)
|
||||
.Cast<PlayerCharacter>();
|
||||
foreach (var actor in actors) {
|
||||
var payload = new PlayerPayload(this.Plugin.Interface.Data, actor.Name, actor.HomeWorld.Id);
|
||||
var payload = new PlayerPayload(this.Plugin.Interface.Data, actor.Name.TextValue, actor.HomeWorld.Id);
|
||||
Payload[] payloads = {payload};
|
||||
this.Plugin.Interface.Framework.Gui.Chat.PrintChat(new XivChatEntry {
|
||||
MessageBytes = new SeString(payloads).Encode(),
|
||||
Message = new SeString(payloads),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -390,10 +393,10 @@ namespace PeepingTom {
|
|||
var target = this.GetCurrentTarget();
|
||||
|
||||
if (target != null) {
|
||||
var payload = new PlayerPayload(this.Plugin.Interface.Data, target.Name, target.HomeWorld.Id);
|
||||
var payload = new PlayerPayload(this.Plugin.Interface.Data, target.Name.TextValue, target.HomeWorld.Id);
|
||||
Payload[] payloads = {payload};
|
||||
this.Plugin.Interface.Framework.Gui.Chat.PrintChat(new XivChatEntry {
|
||||
MessageBytes = new SeString(payloads).Encode(),
|
||||
Message = new SeString(payloads),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -414,18 +417,18 @@ 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<int, Actor>? actors = null;
|
||||
Dictionary<uint, GameObject>? objects = null;
|
||||
if (targeting.Count + (previousTargeters?.Count ?? 0) > 1) {
|
||||
var dict = new Dictionary<int, Actor>();
|
||||
foreach (var actor in this.Plugin.Interface.ClientState.Actors) {
|
||||
if (dict.ContainsKey(actor.ActorId) || actor.ObjectKind != Dalamud.Game.ClientState.Actors.ObjectKind.Player) {
|
||||
var dict = new Dictionary<uint, GameObject>();
|
||||
foreach (var obj in this.Plugin.ObjectTable) {
|
||||
if (dict.ContainsKey(obj.ObjectId) || obj.ObjectKind != ObjectKind.Player) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dict.Add(actor.ActorId, actor);
|
||||
dict.Add(obj.ObjectId, obj);
|
||||
}
|
||||
|
||||
actors = dict;
|
||||
objects = dict;
|
||||
}
|
||||
|
||||
var flags = ImGuiWindowFlags.None;
|
||||
|
@ -465,37 +468,38 @@ namespace PeepingTom {
|
|||
// }
|
||||
|
||||
foreach (var targeter in targeting) {
|
||||
Actor? actor = null;
|
||||
actors?.TryGetValue(targeter.ActorId, out actor);
|
||||
this.AddEntry(targeter, actor, ref anyHovered);
|
||||
GameObject? obj = null;
|
||||
objects?.TryGetValue(targeter.ObjectId, 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.ActorId != old.ActorId))
|
||||
.Where(old => targeting.All(actor => actor.ObjectId != old.ObjectId))
|
||||
.Take(this.Plugin.Config.NumHistory);
|
||||
// add previous targeters to the list
|
||||
foreach (var oldTargeter in previous) {
|
||||
Actor? actor = null;
|
||||
actors?.TryGetValue(oldTargeter.ActorId, out actor);
|
||||
this.AddEntry(oldTargeter, actor, ref anyHovered, ImGuiSelectableFlags.Disabled);
|
||||
GameObject? obj = null;
|
||||
objects?.TryGetValue(oldTargeter.ObjectId, out obj);
|
||||
this.AddEntry(oldTargeter, obj, ref anyHovered, ImGuiSelectableFlags.Disabled);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndListBox();
|
||||
}
|
||||
|
||||
if (this.Plugin.Config.FocusTargetOnHover && !anyHovered && this.PreviousFocus.Get(out var previousFocus)) {
|
||||
if (previousFocus == null) {
|
||||
this.Plugin.Interface.ClientState.Targets.SetFocusTarget(null);
|
||||
var previousFocus = this.PreviousFocus;
|
||||
if (this.Plugin.Config.FocusTargetOnHover && !anyHovered && previousFocus != null) {
|
||||
if (previousFocus == uint.MaxValue) {
|
||||
this.Plugin.TargetManager.FocusTarget = null;
|
||||
} else {
|
||||
var actor = this.Plugin.Interface.ClientState.Actors.FirstOrDefault(a => a.ActorId == previousFocus.ActorId);
|
||||
var actor = this.Plugin.ObjectTable.FirstOrDefault(a => a.ObjectId == previousFocus);
|
||||
// either target the actor if still present or target nothing
|
||||
this.Plugin.Interface.ClientState.Targets.SetFocusTarget(actor);
|
||||
this.Plugin.TargetManager.FocusTarget = actor;
|
||||
}
|
||||
|
||||
this.PreviousFocus = new Optional<Actor>();
|
||||
this.PreviousFocus = null;
|
||||
}
|
||||
|
||||
ImGui.End();
|
||||
|
@ -515,10 +519,10 @@ namespace PeepingTom {
|
|||
ImGui.EndTooltip();
|
||||
}
|
||||
|
||||
private void AddEntry(Targeter targeter, Actor? actor, ref bool anyHovered, ImGuiSelectableFlags flags = ImGuiSelectableFlags.None) {
|
||||
private void AddEntry(Targeter targeter, GameObject? obj, ref bool anyHovered, ImGuiSelectableFlags flags = ImGuiSelectableFlags.None) {
|
||||
ImGui.BeginGroup();
|
||||
|
||||
ImGui.Selectable(targeter.Name, false, flags);
|
||||
ImGui.Selectable(targeter.Name.TextValue, false, flags);
|
||||
|
||||
if (this.Plugin.Config.ShowTimestamps) {
|
||||
var time = DateTime.UtcNow - targeter.When >= TimeSpan.FromDays(1)
|
||||
|
@ -543,48 +547,44 @@ namespace PeepingTom {
|
|||
var left = hover && ImGui.IsMouseClicked(ImGuiMouseButton.Left);
|
||||
var right = hover && ImGui.IsMouseClicked(ImGuiMouseButton.Right);
|
||||
|
||||
actor ??= this.Plugin.Interface.ClientState.Actors
|
||||
.FirstOrDefault(a => a.ActorId == targeter.ActorId);
|
||||
obj ??= this.Plugin.ObjectTable.FirstOrDefault(a => a.ObjectId == targeter.ObjectId);
|
||||
|
||||
// don't count as hovered if the actor isn't here (clears focus target when hovering missing actors)
|
||||
if (actor != null) {
|
||||
if (obj != null) {
|
||||
anyHovered |= hover;
|
||||
}
|
||||
|
||||
if (this.Plugin.Config.FocusTargetOnHover && hover && actor != null) {
|
||||
if (!this.PreviousFocus.Present) {
|
||||
this.PreviousFocus = new Optional<Actor>(this.Plugin.Interface.ClientState.Targets.FocusTarget);
|
||||
}
|
||||
|
||||
this.Plugin.Interface.ClientState.Targets.SetFocusTarget(actor);
|
||||
if (this.Plugin.Config.FocusTargetOnHover && hover && obj != null) {
|
||||
this.PreviousFocus ??= this.Plugin.TargetManager.FocusTarget?.ObjectId ?? uint.MaxValue;
|
||||
this.Plugin.TargetManager.FocusTarget = obj;
|
||||
}
|
||||
|
||||
if (left) {
|
||||
if (this.Plugin.Config.OpenExamine && ImGui.GetIO().KeyAlt) {
|
||||
if (actor != null) {
|
||||
this.Plugin.Common.Functions.Examine.OpenExamineWindow(actor);
|
||||
if (obj != null) {
|
||||
this.Plugin.Common.Functions.Examine.OpenExamineWindow(obj);
|
||||
} else {
|
||||
var error = string.Format(Language.ExamineErrorToast, targeter.Name);
|
||||
this.Plugin.Interface.Framework.Gui.Toast.ShowError(error);
|
||||
this.Plugin.ToastGui.ShowError(error);
|
||||
}
|
||||
} else {
|
||||
var payload = new PlayerPayload(this.Plugin.Interface.Data, targeter.Name, targeter.HomeWorld.Id);
|
||||
Payload[] payloads = {payload};
|
||||
this.Plugin.Interface.Framework.Gui.Chat.PrintChat(new XivChatEntry {
|
||||
MessageBytes = new SeString(payloads).Encode(),
|
||||
var payload = new PlayerPayload(targeter.Name.TextValue, targeter.HomeWorldId);
|
||||
Payload[] payloads = { payload };
|
||||
this.Plugin.ChatGui.PrintChat(new XivChatEntry {
|
||||
Message = new SeString(payloads),
|
||||
});
|
||||
}
|
||||
} else if (right && actor != null) {
|
||||
this.Plugin.Interface.ClientState.Targets.SetCurrentTarget(actor);
|
||||
} else if (right && obj != null) {
|
||||
this.Plugin.TargetManager.Target = obj;
|
||||
}
|
||||
}
|
||||
|
||||
private void MarkPlayer(Actor? player, Vector4 colour, float size) {
|
||||
private void MarkPlayer(GameObject? player, Vector4 colour, float size) {
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.Plugin.Interface.Framework.Gui.WorldToScreen(player.Position, out var screenPos)) {
|
||||
if (!this.Plugin.GameGui.WorldToScreen(player.Position, out var screenPos)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -601,18 +601,18 @@ namespace PeepingTom {
|
|||
}
|
||||
|
||||
private PlayerCharacter? GetCurrentTarget() {
|
||||
var player = this.Plugin.Interface.ClientState.LocalPlayer;
|
||||
var player = this.Plugin.ClientState.LocalPlayer;
|
||||
if (player == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var targetId = player.TargetActorID;
|
||||
var targetId = player.TargetObjectId;
|
||||
if (targetId <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.Plugin.Interface.ClientState.Actors
|
||||
.Where(actor => actor.ActorId == targetId && actor is PlayerCharacter)
|
||||
return this.Plugin.ObjectTable
|
||||
.Where(actor => actor.ObjectId == targetId && actor is PlayerCharacter)
|
||||
.Select(actor => actor as PlayerCharacter)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
using Dalamud.Game.ClientState.Actors.Types;
|
||||
using Dalamud.Game.Internal;
|
||||
using Dalamud.Plugin;
|
||||
using NAudio.Wave;
|
||||
using NAudio.Wave;
|
||||
using Resourcer;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -9,110 +6,78 @@ using System.Diagnostics;
|
|||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.Text;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using PeepingTom.Ipc;
|
||||
using PeepingTom.Resources;
|
||||
|
||||
namespace PeepingTom {
|
||||
internal class TargetWatcher : IDisposable {
|
||||
private PeepingTomPlugin Plugin { get; }
|
||||
|
||||
private Stopwatch? Watch { get; set; }
|
||||
private Stopwatch UpdateWatch { get; } = new();
|
||||
private Stopwatch? SoundWatch { get; set; }
|
||||
private int LastTargetAmount { get; set; }
|
||||
|
||||
private volatile bool _stop;
|
||||
private volatile bool _needsUpdate = true;
|
||||
private Thread? Thread { get; set; }
|
||||
|
||||
private readonly object _dataMutex = new();
|
||||
private TargetThreadData? Data { get; set; }
|
||||
|
||||
private readonly Mutex _currentMutex = new();
|
||||
private Targeter[] Current { get; set; } = Array.Empty<Targeter>();
|
||||
|
||||
public IReadOnlyCollection<Targeter> CurrentTargeters {
|
||||
get {
|
||||
this._currentMutex.WaitOne();
|
||||
var current = this.Current.ToArray();
|
||||
this._currentMutex.ReleaseMutex();
|
||||
return current;
|
||||
}
|
||||
}
|
||||
public IReadOnlyCollection<Targeter> CurrentTargeters => this.Current;
|
||||
|
||||
private readonly Mutex _previousMutex = new();
|
||||
private List<Targeter> Previous { get; } = new();
|
||||
|
||||
public IReadOnlyCollection<Targeter> PreviousTargeters {
|
||||
get {
|
||||
this._previousMutex.WaitOne();
|
||||
var previous = this.Previous.ToArray();
|
||||
this._previousMutex.ReleaseMutex();
|
||||
return previous;
|
||||
}
|
||||
}
|
||||
public IReadOnlyCollection<Targeter> PreviousTargeters => this.Previous;
|
||||
|
||||
public TargetWatcher(PeepingTomPlugin plugin) {
|
||||
this.Plugin = plugin;
|
||||
this.UpdateWatch.Start();
|
||||
|
||||
this.Plugin.Framework.Update += this.OnFrameworkUpdate;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
this.Plugin.Framework.Update -= this.OnFrameworkUpdate;
|
||||
}
|
||||
|
||||
public void ClearPrevious() {
|
||||
this._previousMutex.WaitOne();
|
||||
this.Previous.Clear();
|
||||
this._previousMutex.ReleaseMutex();
|
||||
}
|
||||
|
||||
public void StartThread() {
|
||||
this.Thread = new Thread(() => {
|
||||
while (!this._stop) {
|
||||
this.Update();
|
||||
this._needsUpdate = true;
|
||||
Thread.Sleep(this.Plugin.Config.PollFrequency);
|
||||
}
|
||||
});
|
||||
this.Thread.Start();
|
||||
}
|
||||
|
||||
public void WaitStopThread() {
|
||||
this._stop = true;
|
||||
this.Thread?.Join();
|
||||
}
|
||||
|
||||
public void OnFrameworkUpdate(Framework framework) {
|
||||
if (!this._needsUpdate || this.Plugin.InPvp) {
|
||||
private void OnFrameworkUpdate(Framework framework) {
|
||||
if (this.Plugin.InPvp) {
|
||||
return;
|
||||
}
|
||||
|
||||
lock (this._dataMutex) {
|
||||
this.Data = new TargetThreadData(this.Plugin.Interface);
|
||||
if (this.UpdateWatch.Elapsed > TimeSpan.FromMilliseconds(this.Plugin.Config.PollFrequency)) {
|
||||
this.Update();
|
||||
}
|
||||
|
||||
this._needsUpdate = false;
|
||||
}
|
||||
|
||||
private void Update() {
|
||||
lock (this._dataMutex) {
|
||||
var player = this.Data?.LocalPlayer;
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// block until lease
|
||||
this._currentMutex.WaitOne();
|
||||
|
||||
// get targeters and set a copy so we can release the mutex faster
|
||||
var current = this.GetTargeting(this.Data!.Actors, player);
|
||||
this.Current = (Targeter[]) current.Clone();
|
||||
|
||||
// release
|
||||
this._currentMutex.ReleaseMutex();
|
||||
var player = this.Plugin.ClientState.LocalPlayer;
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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))) {
|
||||
this.Plugin.IpcManager.SendNewTargeter(newTargeter);
|
||||
}
|
||||
|
||||
foreach (var stopped in this.Current.Where(t => newCurrent.All(c => c.ObjectId != t.ObjectId))) {
|
||||
this.Plugin.IpcManager.SendStoppedTargeting(stopped);
|
||||
}
|
||||
|
||||
this.Current = newCurrent;
|
||||
|
||||
this.HandleHistory(this.Current);
|
||||
|
||||
// play sound if necessary
|
||||
if (this.CanPlaySound()) {
|
||||
this.Watch?.Restart();
|
||||
this.SoundWatch?.Restart();
|
||||
this.PlaySound();
|
||||
}
|
||||
|
||||
|
@ -124,47 +89,44 @@ namespace PeepingTom {
|
|||
return;
|
||||
}
|
||||
|
||||
this._previousMutex.WaitOne();
|
||||
|
||||
foreach (var targeter in targeting) {
|
||||
// add the targeter to the previous list
|
||||
if (this.Previous.Any(old => old.ActorId == targeter.ActorId)) {
|
||||
this.Previous.RemoveAll(old => old.ActorId == targeter.ActorId);
|
||||
if (this.Previous.Any(old => old.ObjectId == targeter.ObjectId)) {
|
||||
this.Previous.RemoveAll(old => old.ObjectId == targeter.ObjectId);
|
||||
}
|
||||
|
||||
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.ActorId != old.ActorId)) > this.Plugin.Config.NumHistory) {
|
||||
while (this.Previous.Count(old => targeting.All(actor => actor.ObjectId != old.ObjectId)) > this.Plugin.Config.NumHistory) {
|
||||
this.Previous.RemoveAt(this.Previous.Count - 1);
|
||||
}
|
||||
|
||||
this._previousMutex.ReleaseMutex();
|
||||
}
|
||||
|
||||
private Targeter[] GetTargeting(IEnumerable<Actor> actors, Actor player) {
|
||||
return actors
|
||||
.Where(actor => actor.TargetActorID == player.ActorId && actor is PlayerCharacter)
|
||||
private Targeter[] GetTargeting(IEnumerable<GameObject> objects, GameObject player) {
|
||||
return objects
|
||||
.Where(obj => obj.TargetObjectId == player.ObjectId && obj is PlayerCharacter)
|
||||
// .Where(obj => Marshal.ReadByte(obj.Address + ActorOffsets.PlayerCharacterTargetActorId + 4) == 0)
|
||||
.Cast<PlayerCharacter>()
|
||||
.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.ActorId != player.ActorId)
|
||||
.Where(actor => this.Plugin.Config.LogSelf || actor.ObjectId != player.ObjectId)
|
||||
.Select(actor => new Targeter(actor))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static byte GetStatus(Actor actor) {
|
||||
private static byte GetStatus(GameObject actor) {
|
||||
var statusPtr = actor.Address + 0x1980; // updated 5.4
|
||||
return Marshal.ReadByte(statusPtr);
|
||||
}
|
||||
|
||||
private static bool InCombat(Actor actor) => (GetStatus(actor) & 2) > 0;
|
||||
private static bool InCombat(GameObject actor) => (GetStatus(actor) & 2) > 0;
|
||||
|
||||
private static bool InParty(Actor actor) => (GetStatus(actor) & 16) > 0;
|
||||
private static bool InParty(GameObject actor) => (GetStatus(actor) & 16) > 0;
|
||||
|
||||
private static bool InAlliance(Actor actor) => (GetStatus(actor) & 32) > 0;
|
||||
private static bool InAlliance(GameObject actor) => (GetStatus(actor) & 32) > 0;
|
||||
|
||||
private bool CanPlaySound() {
|
||||
if (!this.Plugin.Config.PlaySoundOnTarget) {
|
||||
|
@ -179,12 +141,12 @@ namespace PeepingTom {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (this.Watch == null) {
|
||||
this.Watch = new Stopwatch();
|
||||
if (this.SoundWatch == null) {
|
||||
this.SoundWatch = new Stopwatch();
|
||||
return true;
|
||||
}
|
||||
|
||||
var secs = this.Watch.Elapsed.TotalSeconds;
|
||||
var secs = this.SoundWatch.Elapsed.TotalSeconds;
|
||||
return secs >= this.Plugin.Config.SoundCooldown;
|
||||
}
|
||||
|
||||
|
@ -228,28 +190,10 @@ namespace PeepingTom {
|
|||
}
|
||||
|
||||
private void SendError(string message) {
|
||||
var payloads = new Payload[] {
|
||||
new TextPayload($"[{this.Plugin.Name}] {message}"),
|
||||
};
|
||||
this.Plugin.Interface.Framework.Gui.Chat.PrintChat(new XivChatEntry {
|
||||
MessageBytes = new SeString(payloads).Encode(),
|
||||
this.Plugin.ChatGui.PrintChat(new XivChatEntry {
|
||||
Message = $"[{this.Plugin.Name}] {message}",
|
||||
Type = XivChatType.ErrorMessage,
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
this._currentMutex.Dispose();
|
||||
this._previousMutex.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
internal class TargetThreadData {
|
||||
public PlayerCharacter LocalPlayer { get; }
|
||||
public Actor[] Actors { get; }
|
||||
|
||||
public TargetThreadData(DalamudPluginInterface pi) {
|
||||
this.LocalPlayer = pi.ClientState.LocalPlayer;
|
||||
this.Actors = pi.ClientState.Actors.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
using Dalamud.Game.ClientState.Actors.Resolvers;
|
||||
using Dalamud.Game.ClientState.Actors.Types;
|
||||
using Dalamud.Plugin;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace PeepingTom {
|
||||
public class Targeter {
|
||||
public string Name { get; }
|
||||
public World HomeWorld { get; }
|
||||
public int ActorId { get; }
|
||||
public DateTime When { get; }
|
||||
|
||||
public Targeter(PlayerCharacter character) {
|
||||
this.Name = character.Name;
|
||||
this.HomeWorld = character.HomeWorld;
|
||||
this.ActorId = character.ActorId;
|
||||
this.When = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public PlayerCharacter? GetPlayerCharacter(DalamudPluginInterface pi) {
|
||||
return pi.ClientState.Actors.FirstOrDefault(actor => actor.ActorId == this.ActorId && actor is PlayerCharacter) as PlayerCharacter;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
namespace PeepingTom {
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1716:Identifiers should not match keywords")]
|
||||
public class Optional<T> where T : class {
|
||||
public bool Present { get; }
|
||||
private readonly T? _value;
|
||||
|
||||
public Optional(T? value) {
|
||||
this._value = value;
|
||||
this.Present = true;
|
||||
}
|
||||
|
||||
public Optional() {
|
||||
this.Present = false;
|
||||
}
|
||||
|
||||
public bool Get(out T? value) {
|
||||
value = this._value;
|
||||
return this.Present;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
# Peeping Tom
|
||||
|
||||
This plugin for FFXIVLauncher shows who was or currently is targeting you.
|
||||
|
||||
Icon: Eyes emoji from Twemoji 2.4
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 47.5 47.5"
|
||||
style="enable-background:new 0 0 47.5 47.5;"
|
||||
xml:space="preserve"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
sodipodi:docname="icon.svg"
|
||||
inkscape:export-filename="D:\code\PeepingTom\icon.png"
|
||||
inkscape:export-xdpi="1023.69"
|
||||
inkscape:export-ydpi="1023.69"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"><sodipodi:namedview
|
||||
id="namedview18"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:pageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="17.515789"
|
||||
inkscape:cx="23.721454"
|
||||
inkscape:cy="23.778546"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="1592"
|
||||
inkscape:window-y="32"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2" /><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath16"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path18"
|
||||
d="M 0,38 38,38 38,0 0,0 0,38 Z" /></clipPath></defs><g
|
||||
transform="matrix(1.25,0,0,-1.25,0,47.5)"
|
||||
id="g10"><g
|
||||
id="g12"><g
|
||||
clip-path="url(#clipPath16)"
|
||||
id="g14"><g
|
||||
transform="translate(18,19)"
|
||||
id="g20"><path
|
||||
id="path22"
|
||||
style="fill:#e1e8ed;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 0,-5.522 -3.806,-10 -8.5,-10 -4.694,0 -8.5,4.478 -8.5,10 0,5.523 3.806,10 8.5,10 C -3.806,10 0,5.523 0,0" /></g><g
|
||||
transform="translate(37,19)"
|
||||
id="g24"><path
|
||||
id="path26"
|
||||
style="fill:#e1e8ed;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 0,-5.522 -3.806,-10 -8.5,-10 -4.694,0 -8.5,4.478 -8.5,10 0,5.523 3.806,10 8.5,10 C -3.806,10 0,5.523 0,0" /></g><g
|
||||
transform="translate(9,15)"
|
||||
id="g28"><path
|
||||
id="path30"
|
||||
style="fill:#292f33;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 0,-1.657 -1.343,-3 -3,-3 -1.657,0 -3,1.343 -3,3 0,1.657 1.343,3 3,3 1.657,0 3,-1.343 3,-3" /></g><g
|
||||
transform="translate(28,15)"
|
||||
id="g32"><path
|
||||
id="path34"
|
||||
style="fill:#292f33;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 0,-1.657 -1.344,-3 -3,-3 -1.656,0 -3,1.343 -3,3 0,1.657 1.344,3 3,3 1.656,0 3,-1.343 3,-3" /></g></g></g></g></svg>
|
After Width: | Height: | Size: 3.0 KiB |
Loading…
Reference in New Issue