refactor: clean up old code
This commit is contained in:
parent
f74b81dc20
commit
5935df195d
203
.editorconfig
203
.editorconfig
|
@ -1,203 +0,0 @@
|
||||||
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
|
||||||
root = true
|
|
||||||
|
|
||||||
# C# files
|
|
||||||
[*.{cs,json}]
|
|
||||||
|
|
||||||
#### Core EditorConfig Options ####
|
|
||||||
|
|
||||||
# Indentation and spacing
|
|
||||||
indent_size = 4
|
|
||||||
indent_style = space
|
|
||||||
tab_width = 4
|
|
||||||
|
|
||||||
# New line preferences
|
|
||||||
end_of_line = lf
|
|
||||||
insert_final_newline = true
|
|
||||||
|
|
||||||
[*.cs]
|
|
||||||
|
|
||||||
#### .NET Coding Conventions ####
|
|
||||||
|
|
||||||
# Organize usings
|
|
||||||
dotnet_separate_import_directive_groups = false
|
|
||||||
dotnet_sort_system_directives_first = false
|
|
||||||
file_header_template = unset
|
|
||||||
|
|
||||||
# this. and Me. preferences
|
|
||||||
dotnet_style_qualification_for_event = true:silent
|
|
||||||
dotnet_style_qualification_for_field = true:silent
|
|
||||||
dotnet_style_qualification_for_method = true:silent
|
|
||||||
dotnet_style_qualification_for_property = true:silent
|
|
||||||
|
|
||||||
# Language keywords vs BCL types preferences
|
|
||||||
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
|
|
||||||
dotnet_style_predefined_type_for_member_access = true:silent
|
|
||||||
|
|
||||||
# Parentheses preferences
|
|
||||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
|
|
||||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
|
|
||||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
|
|
||||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
|
|
||||||
|
|
||||||
# Modifier preferences
|
|
||||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
|
|
||||||
|
|
||||||
# Expression-level preferences
|
|
||||||
dotnet_style_coalesce_expression = true:suggestion
|
|
||||||
dotnet_style_collection_initializer = true:suggestion
|
|
||||||
dotnet_style_explicit_tuple_names = true:suggestion
|
|
||||||
dotnet_style_null_propagation = true:suggestion
|
|
||||||
dotnet_style_object_initializer = true:suggestion
|
|
||||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
|
||||||
dotnet_style_prefer_auto_properties = true:silent
|
|
||||||
dotnet_style_prefer_compound_assignment = true:suggestion
|
|
||||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
|
||||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
|
||||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
|
||||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
|
||||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
|
||||||
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
|
||||||
dotnet_style_prefer_simplified_interpolation = true:suggestion
|
|
||||||
|
|
||||||
# Field preferences
|
|
||||||
dotnet_style_readonly_field = true:suggestion
|
|
||||||
|
|
||||||
# Parameter preferences
|
|
||||||
dotnet_code_quality_unused_parameters = all:suggestion
|
|
||||||
|
|
||||||
#### C# Coding Conventions ####
|
|
||||||
|
|
||||||
# var preferences
|
|
||||||
csharp_style_var_elsewhere = false:silent
|
|
||||||
csharp_style_var_for_built_in_types = false:silent
|
|
||||||
csharp_style_var_when_type_is_apparent = false:silent
|
|
||||||
|
|
||||||
# Expression-bodied members
|
|
||||||
csharp_style_expression_bodied_accessors = true:silent
|
|
||||||
csharp_style_expression_bodied_constructors = false:silent
|
|
||||||
csharp_style_expression_bodied_indexers = true:silent
|
|
||||||
csharp_style_expression_bodied_lambdas = true:silent
|
|
||||||
csharp_style_expression_bodied_local_functions = false:silent
|
|
||||||
csharp_style_expression_bodied_methods = false:silent
|
|
||||||
csharp_style_expression_bodied_operators = false:silent
|
|
||||||
csharp_style_expression_bodied_properties = true:silent
|
|
||||||
|
|
||||||
# Pattern matching preferences
|
|
||||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
|
||||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
|
||||||
csharp_style_prefer_switch_expression = true:suggestion
|
|
||||||
|
|
||||||
# Null-checking preferences
|
|
||||||
csharp_style_conditional_delegate_call = true:suggestion
|
|
||||||
|
|
||||||
# Modifier preferences
|
|
||||||
csharp_prefer_static_local_function = true:suggestion
|
|
||||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
|
||||||
|
|
||||||
# Code-block preferences
|
|
||||||
csharp_prefer_braces = true:error
|
|
||||||
csharp_prefer_simple_using_statement = true:suggestion
|
|
||||||
|
|
||||||
# Expression-level preferences
|
|
||||||
csharp_prefer_simple_default_expression = true:suggestion
|
|
||||||
csharp_style_deconstructed_variable_declaration = true:suggestion
|
|
||||||
csharp_style_inlined_variable_declaration = true:suggestion
|
|
||||||
csharp_style_pattern_local_over_anonymous_function = true:suggestion
|
|
||||||
csharp_style_prefer_index_operator = true:suggestion
|
|
||||||
csharp_style_prefer_range_operator = true:suggestion
|
|
||||||
csharp_style_throw_expression = true:suggestion
|
|
||||||
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
|
|
||||||
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
|
|
||||||
|
|
||||||
# 'using' directive preferences
|
|
||||||
csharp_using_directive_placement = outside_namespace:silent
|
|
||||||
|
|
||||||
#### C# Formatting Rules ####
|
|
||||||
|
|
||||||
# New line preferences
|
|
||||||
csharp_new_line_before_catch = false
|
|
||||||
csharp_new_line_before_else = false
|
|
||||||
csharp_new_line_before_finally = false
|
|
||||||
csharp_new_line_before_members_in_anonymous_types = true
|
|
||||||
csharp_new_line_before_members_in_object_initializers = true
|
|
||||||
csharp_new_line_before_open_brace = none
|
|
||||||
csharp_new_line_between_query_expression_clauses = true
|
|
||||||
|
|
||||||
# Indentation preferences
|
|
||||||
csharp_indent_block_contents = true
|
|
||||||
csharp_indent_braces = false
|
|
||||||
csharp_indent_case_contents = true
|
|
||||||
csharp_indent_case_contents_when_block = true
|
|
||||||
csharp_indent_labels = one_less_than_current
|
|
||||||
csharp_indent_switch_labels = true
|
|
||||||
|
|
||||||
# Space preferences
|
|
||||||
csharp_space_after_cast = false
|
|
||||||
csharp_space_after_colon_in_inheritance_clause = true
|
|
||||||
csharp_space_after_comma = true
|
|
||||||
csharp_space_after_dot = false
|
|
||||||
csharp_space_after_keywords_in_control_flow_statements = true
|
|
||||||
csharp_space_after_semicolon_in_for_statement = true
|
|
||||||
csharp_space_around_binary_operators = before_and_after
|
|
||||||
csharp_space_around_declaration_statements = false
|
|
||||||
csharp_space_before_colon_in_inheritance_clause = true
|
|
||||||
csharp_space_before_comma = false
|
|
||||||
csharp_space_before_dot = false
|
|
||||||
csharp_space_before_open_square_brackets = false
|
|
||||||
csharp_space_before_semicolon_in_for_statement = false
|
|
||||||
csharp_space_between_empty_square_brackets = false
|
|
||||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
|
||||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
|
||||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_parentheses = false
|
|
||||||
csharp_space_between_square_brackets = false
|
|
||||||
|
|
||||||
# Wrapping preferences
|
|
||||||
csharp_preserve_single_line_blocks = true
|
|
||||||
csharp_preserve_single_line_statements = true
|
|
||||||
|
|
||||||
#### Naming styles ####
|
|
||||||
|
|
||||||
# Naming rules
|
|
||||||
|
|
||||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
|
||||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
|
||||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
|
||||||
|
|
||||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
|
||||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
|
||||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
|
||||||
|
|
||||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
|
||||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
|
||||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
|
||||||
|
|
||||||
# Symbol specifications
|
|
||||||
|
|
||||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
|
||||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
|
||||||
dotnet_naming_symbols.interface.required_modifiers =
|
|
||||||
|
|
||||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
|
||||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
|
||||||
dotnet_naming_symbols.types.required_modifiers =
|
|
||||||
|
|
||||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
|
||||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
|
||||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
|
||||||
|
|
||||||
# Naming styles
|
|
||||||
|
|
||||||
dotnet_naming_style.pascal_case.required_prefix =
|
|
||||||
dotnet_naming_style.pascal_case.required_suffix =
|
|
||||||
dotnet_naming_style.pascal_case.word_separator =
|
|
||||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
|
||||||
|
|
||||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
|
||||||
dotnet_naming_style.begins_with_i.required_suffix =
|
|
||||||
dotnet_naming_style.begins_with_i.word_separator =
|
|
||||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
|
|
@ -34,6 +34,7 @@ bld/
|
||||||
|
|
||||||
# Visual Studio 2015/2017 cache/options directory
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
.vs/
|
.vs/
|
||||||
|
.idea/
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
#wwwroot/
|
#wwwroot/
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,6 @@ MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Peeping Tom", "Peeping Tom\Peeping Tom.csproj", "{888F98DF-AF1D-4852-8411-11B1FEEFE674}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Peeping Tom", "Peeping Tom\Peeping Tom.csproj", "{888F98DF-AF1D-4852-8411-11B1FEEFE674}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9B879446-A687-4B9D-8628-807CCB8C51AE}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9B879446-A687-4B9D-8628-807CCB8C51AE}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
|
||||||
.editorconfig = .editorconfig
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
|
|
@ -5,20 +5,17 @@ using System.Numerics;
|
||||||
|
|
||||||
namespace PeepingTom {
|
namespace PeepingTom {
|
||||||
[Serializable]
|
[Serializable]
|
||||||
class Configuration : IPluginConfiguration {
|
internal class Configuration : IPluginConfiguration {
|
||||||
public int Version { get; set; } = 1;
|
public int Version { get; set; } = 1;
|
||||||
|
|
||||||
[NonSerialized]
|
private DalamudPluginInterface Interface { get; set; } = null!;
|
||||||
private DalamudPluginInterface pi;
|
|
||||||
|
|
||||||
public bool MarkTargeted { get; set; } = false;
|
public bool MarkTargeted { get; set; }
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2235:Mark all non-serializable fields", Justification = "it works?")]
|
|
||||||
public Vector4 TargetedColour { get; set; } = new Vector4(0f, 1f, 0f, 1f);
|
public Vector4 TargetedColour { get; set; } = new Vector4(0f, 1f, 0f, 1f);
|
||||||
public float TargetedSize { get; set; } = 2f;
|
public float TargetedSize { get; set; } = 2f;
|
||||||
|
|
||||||
public bool MarkTargeting { get; set; } = false;
|
public bool MarkTargeting { get; set; }
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2235:Mark all non-serializable fields", Justification = "it works?")]
|
|
||||||
public Vector4 TargetingColour { get; set; } = new Vector4(1f, 0f, 0f, 1f);
|
public Vector4 TargetingColour { get; set; } = new Vector4(1f, 0f, 0f, 1f);
|
||||||
public float TargetingSize { get; set; } = 2f;
|
public float TargetingSize { get; set; } = 2f;
|
||||||
|
|
||||||
|
@ -29,35 +26,35 @@ namespace PeepingTom {
|
||||||
public int NumHistory { get; set; } = 5;
|
public int NumHistory { get; set; } = 5;
|
||||||
|
|
||||||
public bool LogParty { get; set; } = true;
|
public bool LogParty { get; set; } = true;
|
||||||
public bool LogAlliance { get; set; } = false;
|
public bool LogAlliance { get; set; }
|
||||||
public bool LogInCombat { get; set; } = false;
|
public bool LogInCombat { get; set; }
|
||||||
public bool LogSelf { get; set; } = false;
|
public bool LogSelf { get; set; }
|
||||||
|
|
||||||
public bool FocusTargetOnHover { get; set; } = true;
|
public bool FocusTargetOnHover { get; set; } = true;
|
||||||
public bool OpenExamine { get; set; } = false;
|
public bool OpenExamine { get; set; } = false;
|
||||||
|
|
||||||
public bool PlaySoundOnTarget { get; set; } = false;
|
public bool PlaySoundOnTarget { get; set; }
|
||||||
public string SoundPath { get; set; } = null;
|
public string? SoundPath { get; set; }
|
||||||
public float SoundVolume { get; set; } = 1f;
|
public float SoundVolume { get; set; } = 1f;
|
||||||
public int SoundDevice { get; set; } = -1;
|
public int SoundDevice { get; set; } = -1;
|
||||||
public float SoundCooldown { get; set; } = 10f;
|
public float SoundCooldown { get; set; } = 10f;
|
||||||
public bool PlaySoundWhenClosed { get; set; } = false;
|
public bool PlaySoundWhenClosed { get; set; }
|
||||||
|
|
||||||
public bool OpenOnLogin { get; set; } = false;
|
public bool OpenOnLogin { get; set; }
|
||||||
public bool AllowMovement { get; set; } = true;
|
public bool AllowMovement { get; set; } = true;
|
||||||
public bool AllowResize { get; set; } = true;
|
public bool AllowResize { get; set; } = true;
|
||||||
public bool ShowInCombat { get; set; } = false;
|
public bool ShowInCombat { get; set; }
|
||||||
public bool ShowInInstance { get; set; } = false;
|
public bool ShowInInstance { get; set; }
|
||||||
public bool ShowInCutscenes { get; set; } = false;
|
public bool ShowInCutscenes { get; set; }
|
||||||
|
|
||||||
public int PollFrequency { get; set; } = 100;
|
public int PollFrequency { get; set; } = 100;
|
||||||
|
|
||||||
public void Initialize(DalamudPluginInterface pluginInterface) {
|
public void Initialize(DalamudPluginInterface pluginInterface) {
|
||||||
this.pi = pluginInterface;
|
this.Interface = pluginInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save() {
|
public void Save() {
|
||||||
this.pi.SavePluginConfig(this);
|
this.Interface.SavePluginConfig(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<Project>
|
||||||
|
<Target Name="PackagePlugin" AfterTargets="Build" Condition="'$(Configuration)' == 'Release'">
|
||||||
|
<DalamudPackager ProjectDir="$(ProjectDir)"
|
||||||
|
OutputPath="$(OutputPath)"
|
||||||
|
AssemblyName="$(AssemblyName)"
|
||||||
|
VersionComponents="3"
|
||||||
|
ManifestType="yaml"
|
||||||
|
MakeZip="true"/>
|
||||||
|
</Target>
|
||||||
|
</Project>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||||
|
<Resourcer />
|
||||||
|
</Weavers>
|
|
@ -9,18 +9,16 @@ namespace PeepingTom {
|
||||||
private delegate IntPtr GetListDelegate(IntPtr basePtr);
|
private delegate IntPtr GetListDelegate(IntPtr basePtr);
|
||||||
private delegate long RequestCharInfoDelegate(IntPtr ptr);
|
private delegate long RequestCharInfoDelegate(IntPtr ptr);
|
||||||
|
|
||||||
private readonly PeepingTomPlugin plugin;
|
private PeepingTomPlugin Plugin { get; }
|
||||||
|
|
||||||
private readonly RequestCharInfoDelegate _requestCharInfo = null;
|
private readonly RequestCharInfoDelegate? _requestCharInfo;
|
||||||
|
|
||||||
public GameFunctions(PeepingTomPlugin plugin) {
|
public GameFunctions(PeepingTomPlugin plugin) {
|
||||||
this.plugin = plugin ?? throw new ArgumentNullException(nameof(plugin), "PeepingTomPlugin cannot be null");
|
this.Plugin = plugin ?? throw new ArgumentNullException(nameof(plugin), "PeepingTomPlugin cannot be null");
|
||||||
|
|
||||||
IntPtr rciPtr;
|
IntPtr rciPtr;
|
||||||
try {
|
try {
|
||||||
rciPtr = this.plugin.Interface.TargetModuleScanner.ScanText("48 89 5C 24 ?? 57 48 83 EC 40 BA 3B 01 00 00");
|
rciPtr = this.Plugin.Interface.TargetModuleScanner.ScanText("E8 ?? ?? ?? ?? 83 7B 30 00 74 47");
|
||||||
// old: 48 89 5C 24 ?? 57 48 83 EC 40 BA 1C 01 00 00
|
|
||||||
// old: 48 89 5C 24 ?? 57 48 83 EC 40 BA 1B 01 00 00
|
|
||||||
} catch (KeyNotFoundException) {
|
} catch (KeyNotFoundException) {
|
||||||
rciPtr = IntPtr.Zero;
|
rciPtr = IntPtr.Zero;
|
||||||
}
|
}
|
||||||
|
@ -32,8 +30,8 @@ namespace PeepingTom {
|
||||||
this._requestCharInfo = Marshal.GetDelegateForFunctionPointer<RequestCharInfoDelegate>(rciPtr);
|
this._requestCharInfo = Marshal.GetDelegateForFunctionPointer<RequestCharInfoDelegate>(rciPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IntPtr FollowPtrChain(IntPtr start, int[] offsets) {
|
private static IntPtr FollowPtrChain(IntPtr start, IEnumerable<int> offsets) {
|
||||||
foreach (int offset in offsets) {
|
foreach (var offset in offsets) {
|
||||||
start = Marshal.ReadIntPtr(start, offset);
|
start = Marshal.ReadIntPtr(start, offset);
|
||||||
if (start == IntPtr.Zero) {
|
if (start == IntPtr.Zero) {
|
||||||
break;
|
break;
|
||||||
|
@ -48,12 +46,12 @@ namespace PeepingTom {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IntPtr framework = this.plugin.Interface.Framework.Address.BaseAddress;
|
var framework = this.Plugin.Interface.Framework.Address.BaseAddress;
|
||||||
|
|
||||||
IntPtr getListPtr = FollowPtrChain(framework, new int[] { 0x29f8, 0, 0x110 });
|
var getListPtr = FollowPtrChain(framework, new[] { 0x29f8, 0, 0x110 });
|
||||||
var getList = Marshal.GetDelegateForFunctionPointer<GetListDelegate>(getListPtr);
|
var getList = Marshal.GetDelegateForFunctionPointer<GetListDelegate>(getListPtr);
|
||||||
IntPtr list = getList(Marshal.ReadIntPtr(framework + 0x29f8));
|
var list = getList(Marshal.ReadIntPtr(framework + 0x29f8));
|
||||||
IntPtr rciData = Marshal.ReadIntPtr(list + 0x188);
|
var rciData = Marshal.ReadIntPtr(list + 0x188);
|
||||||
|
|
||||||
Marshal.WriteInt32(rciData + 0x28, actor.ActorId);
|
Marshal.WriteInt32(rciData + 0x28, actor.ActorId);
|
||||||
Marshal.WriteInt32(rciData + 0x2c, actor.ActorId);
|
Marshal.WriteInt32(rciData + 0x2c, actor.ActorId);
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
// This file is used by Code Analysis to maintain SuppressMessage
|
|
||||||
// attributes that are applied to this project.
|
|
||||||
// Project-level suppressions either have no target or are given
|
|
||||||
// a specific target and scoped to a namespace, type, member, etc.
|
|
||||||
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
[assembly: SuppressMessage("Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "Will add later and don't need warnings clogging up", Scope = "module")]
|
|
|
@ -1,116 +1,44 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Import Project="..\packages\Microsoft.CodeAnalysis.FxCopAnalyzers.2.9.6\build\Microsoft.CodeAnalysis.FxCopAnalyzers.props" Condition="Exists('..\packages\Microsoft.CodeAnalysis.FxCopAnalyzers.2.9.6\build\Microsoft.CodeAnalysis.FxCopAnalyzers.props')" />
|
|
||||||
<Import Project="..\packages\Microsoft.NetFramework.Analyzers.2.9.6\build\Microsoft.NetFramework.Analyzers.props" Condition="Exists('..\packages\Microsoft.NetFramework.Analyzers.2.9.6\build\Microsoft.NetFramework.Analyzers.props')" />
|
|
||||||
<Import Project="..\packages\Microsoft.NetCore.Analyzers.2.9.6\build\Microsoft.NetCore.Analyzers.props" Condition="Exists('..\packages\Microsoft.NetCore.Analyzers.2.9.6\build\Microsoft.NetCore.Analyzers.props')" />
|
|
||||||
<Import Project="..\packages\Microsoft.CodeQuality.Analyzers.2.9.6\build\Microsoft.CodeQuality.Analyzers.props" Condition="Exists('..\packages\Microsoft.CodeQuality.Analyzers.2.9.6\build\Microsoft.CodeQuality.Analyzers.props')" />
|
|
||||||
<Import Project="..\packages\Microsoft.CodeAnalysis.VersionCheckAnalyzer.2.9.6\build\Microsoft.CodeAnalysis.VersionCheckAnalyzer.props" Condition="Exists('..\packages\Microsoft.CodeAnalysis.VersionCheckAnalyzer.2.9.6\build\Microsoft.CodeAnalysis.VersionCheckAnalyzer.props')" />
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<TargetFramework>net48</TargetFramework>
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProjectGuid>{888F98DF-AF1D-4852-8411-11B1FEEFE674}</ProjectGuid>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
||||||
<RootNamespace>PeepingTom</RootNamespace>
|
<RootNamespace>PeepingTom</RootNamespace>
|
||||||
|
<AssemblyVersion>1.5.2</AssemblyVersion>
|
||||||
|
<FileVersion>1.5.2</FileVersion>
|
||||||
|
<LangVersion>8</LangVersion>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
<AssemblyName>PeepingTom</AssemblyName>
|
<AssemblyName>PeepingTom</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
|
||||||
<FileAlignment>512</FileAlignment>
|
|
||||||
<Deterministic>true</Deterministic>
|
|
||||||
<NuGetPackageImportStamp>
|
|
||||||
</NuGetPackageImportStamp>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Dalamud">
|
<EmbeddedResource Include="Resources\target.wav" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Dalamud, Version=5.2.1.1, Culture=neutral, PublicKeyToken=null">
|
||||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\Dalamud.dll</HintPath>
|
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\Dalamud.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="ImGui.NET">
|
<Reference Include="ImGui.NET, Version=1.72.0.0, Culture=neutral, PublicKeyToken=null">
|
||||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGui.NET.dll</HintPath>
|
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGui.NET.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="ImGuiScene">
|
<Reference Include="ImGuiScene, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
|
||||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGuiScene.dll</HintPath>
|
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGuiScene.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="NAudio, Version=1.10.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="SharpDX.Mathematics, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1">
|
||||||
<HintPath>..\packages\NAudio.1.10.0\lib\net35\NAudio.dll</HintPath>
|
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\SharpDX.Mathematics.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="SharpDX.Mathematics, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1" />
|
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Reference Include="System.Numerics" />
|
|
||||||
<Reference Include="System.Xml.Linq" />
|
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
|
||||||
<Reference Include="Microsoft.CSharp" />
|
|
||||||
<Reference Include="System.Data" />
|
|
||||||
<Reference Include="System.Net.Http" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Configuration.cs" />
|
<PackageReference Include="DalamudPackager" Version="1.0.1" />
|
||||||
<Compile Include="GameFunctions.cs" />
|
<PackageReference Include="Fody" Version="6.3.0">
|
||||||
<Compile Include="GlobalSuppressions.cs" />
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<Compile Include="Plugin.cs" />
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<Compile Include="PluginUI.cs" />
|
</PackageReference>
|
||||||
<Compile Include="Targeting.cs" />
|
<PackageReference Include="Resourcer.Fody" Version="1.8.0">
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<Compile Include="Properties\Resources.Designer.cs">
|
</PackageReference>
|
||||||
<AutoGen>True</AutoGen>
|
<PackageReference Include="NAudio" Version="1.10.0" />
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<DependentUpon>Resources.resx</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="TargetWatcher.cs" />
|
|
||||||
<Compile Include="Util.cs" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<EmbeddedResource Include="Properties\Resources.resx">
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
|
||||||
</EmbeddedResource>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="packages.config" />
|
|
||||||
<None Include="Resources\target.wav" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="PeepingTom.json" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.VersionCheckAnalyzer.2.9.6\analyzers\dotnet\cs\Microsoft.CodeAnalysis.VersionCheckAnalyzer.resources.dll" />
|
|
||||||
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.VersionCheckAnalyzer.2.9.6\analyzers\dotnet\Microsoft.CodeAnalysis.VersionCheckAnalyzer.dll" />
|
|
||||||
<Analyzer Include="..\packages\Microsoft.CodeQuality.Analyzers.2.9.6\analyzers\dotnet\cs\Humanizer.dll" />
|
|
||||||
<Analyzer Include="..\packages\Microsoft.CodeQuality.Analyzers.2.9.6\analyzers\dotnet\cs\Microsoft.CodeQuality.Analyzers.dll" />
|
|
||||||
<Analyzer Include="..\packages\Microsoft.CodeQuality.Analyzers.2.9.6\analyzers\dotnet\cs\Microsoft.CodeQuality.CSharp.Analyzers.dll" />
|
|
||||||
<Analyzer Include="..\packages\Microsoft.NetCore.Analyzers.2.9.6\analyzers\dotnet\cs\Microsoft.NetCore.Analyzers.dll" />
|
|
||||||
<Analyzer Include="..\packages\Microsoft.NetCore.Analyzers.2.9.6\analyzers\dotnet\cs\Microsoft.NetCore.CSharp.Analyzers.dll" />
|
|
||||||
<Analyzer Include="..\packages\Microsoft.NetFramework.Analyzers.2.9.6\analyzers\dotnet\cs\Microsoft.NetFramework.Analyzers.dll" />
|
|
||||||
<Analyzer Include="..\packages\Microsoft.NetFramework.Analyzers.2.9.6\analyzers\dotnet\cs\Microsoft.NetFramework.CSharp.Analyzers.dll" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
|
||||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
|
||||||
<PropertyGroup>
|
|
||||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Error Condition="!Exists('..\packages\Microsoft.CodeAnalysis.VersionCheckAnalyzer.2.9.6\build\Microsoft.CodeAnalysis.VersionCheckAnalyzer.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeAnalysis.VersionCheckAnalyzer.2.9.6\build\Microsoft.CodeAnalysis.VersionCheckAnalyzer.props'))" />
|
|
||||||
<Error Condition="!Exists('..\packages\Microsoft.CodeQuality.Analyzers.2.9.6\build\Microsoft.CodeQuality.Analyzers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeQuality.Analyzers.2.9.6\build\Microsoft.CodeQuality.Analyzers.props'))" />
|
|
||||||
<Error Condition="!Exists('..\packages\Microsoft.NetCore.Analyzers.2.9.6\build\Microsoft.NetCore.Analyzers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.NetCore.Analyzers.2.9.6\build\Microsoft.NetCore.Analyzers.props'))" />
|
|
||||||
<Error Condition="!Exists('..\packages\Microsoft.NetFramework.Analyzers.2.9.6\build\Microsoft.NetFramework.Analyzers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.NetFramework.Analyzers.2.9.6\build\Microsoft.NetFramework.Analyzers.props'))" />
|
|
||||||
<Error Condition="!Exists('..\packages\Microsoft.CodeAnalysis.FxCopAnalyzers.2.9.6\build\Microsoft.CodeAnalysis.FxCopAnalyzers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeAnalysis.FxCopAnalyzers.2.9.6\build\Microsoft.CodeAnalysis.FxCopAnalyzers.props'))" />
|
|
||||||
</Target>
|
|
||||||
</Project>
|
</Project>
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"Author": "ascclemens",
|
|
||||||
"Name": "Peeping Tom",
|
|
||||||
"Description": "Shows who is or was targeting you. /ptom",
|
|
||||||
"InternalName": "PeepingTom",
|
|
||||||
"AssemblyVersion": "1.5.2",
|
|
||||||
"RepoUrl": "https://sr.ht/~jkcclemens/PeepingTom",
|
|
||||||
"ApplicableVersion": "any",
|
|
||||||
"DalamudApiLevel": 2
|
|
||||||
}
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
author: ascclemens
|
||||||
|
name: Peeping Tom
|
||||||
|
description: Shows who is currently or previously was targeting you.
|
||||||
|
repo_url: https://sr.ht/~jkcclemens/PeepingTom
|
|
@ -3,14 +3,14 @@ using Dalamud.Plugin;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace PeepingTom {
|
namespace PeepingTom {
|
||||||
public class PeepingTomPlugin : IDalamudPlugin, IDisposable {
|
public class PeepingTomPlugin : IDalamudPlugin {
|
||||||
public string Name => "Peeping Tom";
|
public string Name => "Peeping Tom";
|
||||||
|
|
||||||
internal DalamudPluginInterface Interface { get; private set; }
|
internal DalamudPluginInterface Interface { get; private set; } = null!;
|
||||||
internal Configuration Config { get; private set; }
|
internal Configuration Config { get; private set; } = null!;
|
||||||
internal PluginUI Ui { get; private set; }
|
internal PluginUi Ui { get; private set; } = null!;
|
||||||
internal TargetWatcher Watcher { get; private set; }
|
internal TargetWatcher Watcher { get; private set; } = null!;
|
||||||
internal GameFunctions GameFunctions { get; private set; }
|
internal GameFunctions GameFunctions { get; private set; } = null!;
|
||||||
|
|
||||||
public void Initialize(DalamudPluginInterface pluginInterface) {
|
public void Initialize(DalamudPluginInterface pluginInterface) {
|
||||||
this.Interface = pluginInterface ?? throw new ArgumentNullException(nameof(pluginInterface), "DalamudPluginInterface argument was null");
|
this.Interface = pluginInterface ?? throw new ArgumentNullException(nameof(pluginInterface), "DalamudPluginInterface argument was null");
|
||||||
|
@ -18,7 +18,7 @@ namespace PeepingTom {
|
||||||
this.Config.Initialize(this.Interface);
|
this.Config.Initialize(this.Interface);
|
||||||
this.Watcher = new TargetWatcher(this);
|
this.Watcher = new TargetWatcher(this);
|
||||||
this.GameFunctions = new GameFunctions(this);
|
this.GameFunctions = new GameFunctions(this);
|
||||||
this.Ui = new PluginUI(this);
|
this.Ui = new PluginUi(this);
|
||||||
|
|
||||||
this.Interface.CommandManager.AddHandler("/ppeepingtom", new CommandInfo(this.OnCommand) {
|
this.Interface.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"
|
HelpMessage = "Use with no arguments to show the list. Use with \"c\" or \"config\" to show the config"
|
||||||
|
@ -33,8 +33,8 @@ namespace PeepingTom {
|
||||||
this.Interface.Framework.OnUpdateEvent += this.Watcher.OnFrameworkUpdate;
|
this.Interface.Framework.OnUpdateEvent += this.Watcher.OnFrameworkUpdate;
|
||||||
this.Interface.ClientState.OnLogin += this.OnLogin;
|
this.Interface.ClientState.OnLogin += this.OnLogin;
|
||||||
this.Interface.ClientState.OnLogout += this.OnLogout;
|
this.Interface.ClientState.OnLogout += this.OnLogout;
|
||||||
this.Interface.UiBuilder.OnBuildUi += this.DrawUI;
|
this.Interface.UiBuilder.OnBuildUi += this.DrawUi;
|
||||||
this.Interface.UiBuilder.OnOpenConfigUi += this.ConfigUI;
|
this.Interface.UiBuilder.OnOpenConfigUi += this.ConfigUi;
|
||||||
|
|
||||||
this.Watcher.StartThread();
|
this.Watcher.StartThread();
|
||||||
}
|
}
|
||||||
|
@ -66,8 +66,8 @@ namespace PeepingTom {
|
||||||
this.Interface.ClientState.OnLogout -= this.OnLogout;
|
this.Interface.ClientState.OnLogout -= this.OnLogout;
|
||||||
this.Watcher.WaitStopThread();
|
this.Watcher.WaitStopThread();
|
||||||
this.Watcher.Dispose();
|
this.Watcher.Dispose();
|
||||||
this.Interface.UiBuilder.OnBuildUi -= DrawUI;
|
this.Interface.UiBuilder.OnBuildUi -= this.DrawUi;
|
||||||
this.Interface.UiBuilder.OnOpenConfigUi -= ConfigUI;
|
this.Interface.UiBuilder.OnOpenConfigUi -= this.ConfigUi;
|
||||||
this.Interface.CommandManager.RemoveHandler("/ppeepingtom");
|
this.Interface.CommandManager.RemoveHandler("/ppeepingtom");
|
||||||
this.Interface.CommandManager.RemoveHandler("/ptom");
|
this.Interface.CommandManager.RemoveHandler("/ptom");
|
||||||
this.Interface.CommandManager.RemoveHandler("/ppeep");
|
this.Interface.CommandManager.RemoveHandler("/ppeep");
|
||||||
|
@ -79,11 +79,11 @@ namespace PeepingTom {
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawUI() {
|
private void DrawUi() {
|
||||||
this.Ui.Draw();
|
this.Ui.Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConfigUI(object sender, EventArgs args) {
|
private void ConfigUi(object sender, EventArgs args) {
|
||||||
this.Ui.SettingsOpen = true;
|
this.Ui.SettingsOpen = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,559 +0,0 @@
|
||||||
using Dalamud.Game.Chat;
|
|
||||||
using Dalamud.Game.Chat.SeStringHandling;
|
|
||||||
using Dalamud.Game.Chat.SeStringHandling.Payloads;
|
|
||||||
using Dalamud.Game.ClientState;
|
|
||||||
using Dalamud.Game.ClientState.Actors.Types;
|
|
||||||
using ImGuiNET;
|
|
||||||
using NAudio.Wave;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Numerics;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace PeepingTom {
|
|
||||||
class PluginUI : IDisposable {
|
|
||||||
private readonly PeepingTomPlugin plugin;
|
|
||||||
|
|
||||||
private Optional<Actor> previousFocus = new Optional<Actor>();
|
|
||||||
|
|
||||||
private bool _wantsOpen = false;
|
|
||||||
public bool WantsOpen {
|
|
||||||
get => this._wantsOpen;
|
|
||||||
set => this._wantsOpen = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Visible { get; private set; }
|
|
||||||
|
|
||||||
private bool _settingsOpen = false;
|
|
||||||
public bool SettingsOpen {
|
|
||||||
get => this._settingsOpen;
|
|
||||||
set => this._settingsOpen = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginUI(PeepingTomPlugin plugin) {
|
|
||||||
this.plugin = plugin ?? throw new ArgumentNullException(nameof(plugin), "PeepingTomPlugin cannot be null");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose() {
|
|
||||||
this.WantsOpen = false;
|
|
||||||
this.SettingsOpen = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Draw() {
|
|
||||||
if (this.SettingsOpen) {
|
|
||||||
ShowSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool inCombat = this.plugin.Interface.ClientState.Condition[ConditionFlag.InCombat];
|
|
||||||
bool inInstance = this.plugin.Interface.ClientState.Condition[ConditionFlag.BoundByDuty]
|
|
||||||
|| this.plugin.Interface.ClientState.Condition[ConditionFlag.BoundByDuty56]
|
|
||||||
|| this.plugin.Interface.ClientState.Condition[ConditionFlag.BoundByDuty95];
|
|
||||||
bool inCutscene = this.plugin.Interface.ClientState.Condition[ConditionFlag.WatchingCutscene]
|
|
||||||
|| this.plugin.Interface.ClientState.Condition[ConditionFlag.WatchingCutscene78]
|
|
||||||
|| this.plugin.Interface.ClientState.Condition[ConditionFlag.OccupiedInCutSceneEvent];
|
|
||||||
|
|
||||||
// FIXME: this could just be a boolean expression
|
|
||||||
bool shouldBeShown = this.WantsOpen;
|
|
||||||
if (inCombat && !this.plugin.Config.ShowInCombat) {
|
|
||||||
shouldBeShown = false;
|
|
||||||
} else if (inInstance && !this.plugin.Config.ShowInInstance) {
|
|
||||||
shouldBeShown = false;
|
|
||||||
} else if (inCutscene && !this.plugin.Config.ShowInCutscenes) {
|
|
||||||
shouldBeShown = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Visible = shouldBeShown;
|
|
||||||
|
|
||||||
if (shouldBeShown) {
|
|
||||||
ShowMainWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
var flags = ImGuiWindowFlags.NoBackground
|
|
||||||
| ImGuiWindowFlags.NoTitleBar
|
|
||||||
| ImGuiWindowFlags.NoNav
|
|
||||||
| ImGuiWindowFlags.NoNavInputs
|
|
||||||
| ImGuiWindowFlags.NoFocusOnAppearing
|
|
||||||
| ImGuiWindowFlags.NoNavFocus
|
|
||||||
| ImGuiWindowFlags.NoInputs
|
|
||||||
| ImGuiWindowFlags.NoMouseInputs
|
|
||||||
| ImGuiWindowFlags.NoSavedSettings
|
|
||||||
| ImGuiWindowFlags.NoDecoration
|
|
||||||
| ImGuiWindowFlags.NoScrollWithMouse;
|
|
||||||
if (ImGui.Begin("Peeping Tom targeting indicator dummy window", flags)) {
|
|
||||||
if (this.plugin.Config.MarkTargeted) {
|
|
||||||
MarkPlayer(GetCurrentTarget(), this.plugin.Config.TargetedColour, this.plugin.Config.TargetedSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.plugin.Config.MarkTargeting) {
|
|
||||||
PlayerCharacter player = this.plugin.Interface.ClientState.LocalPlayer;
|
|
||||||
if (player != null) {
|
|
||||||
PlayerCharacter[] targeting = this.plugin.Watcher.CurrentTargeters
|
|
||||||
.Select(targeter => this.plugin.Interface.ClientState.Actors.FirstOrDefault(actor => actor.ActorId == targeter.ActorId))
|
|
||||||
.Where(targeter => targeter != null)
|
|
||||||
.Select(targeter => targeter as PlayerCharacter)
|
|
||||||
.ToArray();
|
|
||||||
foreach (PlayerCharacter targeter in targeting) {
|
|
||||||
MarkPlayer(targeter, this.plugin.Config.TargetingColour, this.plugin.Config.TargetingSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ShowSettings() {
|
|
||||||
ImGui.SetNextWindowSize(new Vector2(700, 250));
|
|
||||||
if (ImGui.Begin($"{this.plugin.Name} settings", ref this._settingsOpen, ImGuiWindowFlags.NoResize)) {
|
|
||||||
if (ImGui.BeginTabBar("##settings-tabs")) {
|
|
||||||
if (ImGui.BeginTabItem("Markers")) {
|
|
||||||
bool markTargeted = this.plugin.Config.MarkTargeted;
|
|
||||||
if (ImGui.Checkbox("Mark your target", ref markTargeted)) {
|
|
||||||
this.plugin.Config.MarkTargeted = markTargeted;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector4 targetedColour = this.plugin.Config.TargetedColour;
|
|
||||||
if (ImGui.ColorEdit4("Target mark colour", ref targetedColour)) {
|
|
||||||
this.plugin.Config.TargetedColour = targetedColour;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
float targetedSize = this.plugin.Config.TargetedSize;
|
|
||||||
if (ImGui.DragFloat("Target mark size", ref targetedSize, 0.01f, 0f, 15f)) {
|
|
||||||
targetedSize = Math.Max(0f, targetedSize);
|
|
||||||
this.plugin.Config.TargetedSize = targetedSize;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.Spacing();
|
|
||||||
|
|
||||||
bool markTargeting = this.plugin.Config.MarkTargeting;
|
|
||||||
if (ImGui.Checkbox("Mark targeting you", ref markTargeting)) {
|
|
||||||
this.plugin.Config.MarkTargeting = markTargeting;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector4 targetingColour = this.plugin.Config.TargetingColour;
|
|
||||||
if (ImGui.ColorEdit4("Targeting mark colour", ref targetingColour)) {
|
|
||||||
this.plugin.Config.TargetingColour = targetingColour;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
float targetingSize = this.plugin.Config.TargetingSize;
|
|
||||||
if (ImGui.DragFloat("Targeting mark size", ref targetingSize, 0.01f, 0f, 15f)) {
|
|
||||||
targetingSize = Math.Max(0f, targetingSize);
|
|
||||||
this.plugin.Config.TargetingSize = targetingSize;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.EndTabItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.BeginTabItem("Filters")) {
|
|
||||||
bool showParty = this.plugin.Config.LogParty;
|
|
||||||
if (ImGui.Checkbox("Log party members", ref showParty)) {
|
|
||||||
this.plugin.Config.LogParty = showParty;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool logAlliance = this.plugin.Config.LogAlliance;
|
|
||||||
if (ImGui.Checkbox("Log alliance members", ref logAlliance)) {
|
|
||||||
this.plugin.Config.LogAlliance = logAlliance;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool logInCombat = this.plugin.Config.LogInCombat;
|
|
||||||
if (ImGui.Checkbox("Log targeters engaged in combat", ref logInCombat)) {
|
|
||||||
this.plugin.Config.LogInCombat = logInCombat;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool logSelf = this.plugin.Config.LogSelf;
|
|
||||||
if (ImGui.Checkbox("Log yourself", ref logSelf)) {
|
|
||||||
this.plugin.Config.LogSelf = logSelf;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.EndTabItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.BeginTabItem("Behaviour")) {
|
|
||||||
bool focusTarget = this.plugin.Config.FocusTargetOnHover;
|
|
||||||
if (ImGui.Checkbox("Focus target on hover", ref focusTarget)) {
|
|
||||||
this.plugin.Config.FocusTargetOnHover = focusTarget;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
// bool openExamine = this.plugin.Config.OpenExamine;
|
|
||||||
// if (ImGui.Checkbox("Open examine window on Alt-click", ref openExamine)) {
|
|
||||||
// this.plugin.Config.OpenExamine = openExamine;
|
|
||||||
// this.plugin.Config.Save();
|
|
||||||
// }
|
|
||||||
|
|
||||||
ImGui.EndTabItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.BeginTabItem("Sound")) {
|
|
||||||
bool playSound = this.plugin.Config.PlaySoundOnTarget;
|
|
||||||
if (ImGui.Checkbox("Play sound when targeted", ref playSound)) {
|
|
||||||
this.plugin.Config.PlaySoundOnTarget = playSound;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
string path = this.plugin.Config.SoundPath ?? "";
|
|
||||||
if (ImGui.InputText("Path to audio file", ref path, 1_000)) {
|
|
||||||
path = path.Trim();
|
|
||||||
this.plugin.Config.SoundPath = path.Length == 0 ? null : path;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.Text("Leave this blank to use a built-in sound.");
|
|
||||||
|
|
||||||
float volume = this.plugin.Config.SoundVolume * 100f;
|
|
||||||
if (ImGui.DragFloat("Volume of sound", ref volume, .1f, 0f, 100f, "%.1f%%")) {
|
|
||||||
this.plugin.Config.SoundVolume = Math.Max(0f, Math.Min(1f, volume / 100f));
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
int soundDevice = this.plugin.Config.SoundDevice;
|
|
||||||
string name;
|
|
||||||
if (soundDevice == -1) {
|
|
||||||
name = "Default";
|
|
||||||
} else if (soundDevice > -1 && soundDevice < WaveOut.DeviceCount) {
|
|
||||||
var caps = WaveOut.GetCapabilities(soundDevice);
|
|
||||||
name = caps.ProductName;
|
|
||||||
} else {
|
|
||||||
name = "Invalid device";
|
|
||||||
}
|
|
||||||
if (ImGui.BeginCombo("Output device", name)) {
|
|
||||||
if (ImGui.Selectable("Default")) {
|
|
||||||
this.plugin.Config.SoundDevice = -1;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.Separator();
|
|
||||||
|
|
||||||
for (int deviceNum = 0; deviceNum < WaveOut.DeviceCount; deviceNum++) {
|
|
||||||
var caps = WaveOut.GetCapabilities(deviceNum);
|
|
||||||
if (ImGui.Selectable(caps.ProductName)) {
|
|
||||||
this.plugin.Config.SoundDevice = deviceNum;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.EndCombo();
|
|
||||||
}
|
|
||||||
|
|
||||||
float soundCooldown = this.plugin.Config.SoundCooldown;
|
|
||||||
if (ImGui.DragFloat("Cooldown for sound (seconds)", ref soundCooldown, .01f, 0f, 30f)) {
|
|
||||||
soundCooldown = Math.Max(0f, soundCooldown);
|
|
||||||
this.plugin.Config.SoundCooldown = soundCooldown;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool playWhenClosed = this.plugin.Config.PlaySoundWhenClosed;
|
|
||||||
if (ImGui.Checkbox("Play sound when window is closed", ref playWhenClosed)) {
|
|
||||||
this.plugin.Config.PlaySoundWhenClosed = playWhenClosed;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.EndTabItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.BeginTabItem("Window")) {
|
|
||||||
bool openOnLogin = this.plugin.Config.OpenOnLogin;
|
|
||||||
if (ImGui.Checkbox("Open on login", ref openOnLogin)) {
|
|
||||||
this.plugin.Config.OpenOnLogin = openOnLogin;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool allowMovement = this.plugin.Config.AllowMovement;
|
|
||||||
if (ImGui.Checkbox("Allow moving the main window", ref allowMovement)) {
|
|
||||||
this.plugin.Config.AllowMovement = allowMovement;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool allowResizing = this.plugin.Config.AllowResize;
|
|
||||||
if (ImGui.Checkbox("Allow resizing the main window", ref allowResizing)) {
|
|
||||||
this.plugin.Config.AllowResize = allowResizing;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.Spacing();
|
|
||||||
|
|
||||||
bool showInCombat = this.plugin.Config.ShowInCombat;
|
|
||||||
if (ImGui.Checkbox("Show window while in combat", ref showInCombat)) {
|
|
||||||
this.plugin.Config.ShowInCombat = showInCombat;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool showInInstance = this.plugin.Config.ShowInInstance;
|
|
||||||
if (ImGui.Checkbox("Show window while in instance", ref showInInstance)) {
|
|
||||||
this.plugin.Config.ShowInInstance = showInInstance;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool showInCutscenes = this.plugin.Config.ShowInCutscenes;
|
|
||||||
if (ImGui.Checkbox("Show window while in cutscenes", ref showInCutscenes)) {
|
|
||||||
this.plugin.Config.ShowInCutscenes = showInCutscenes;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.EndTabItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.BeginTabItem("History")) {
|
|
||||||
bool keepHistory = this.plugin.Config.KeepHistory;
|
|
||||||
if (ImGui.Checkbox("Show previous targeters", ref keepHistory)) {
|
|
||||||
this.plugin.Config.KeepHistory = keepHistory;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool historyWhenClosed = this.plugin.Config.HistoryWhenClosed;
|
|
||||||
if (ImGui.Checkbox("Record history when window is closed", ref historyWhenClosed)) {
|
|
||||||
this.plugin.Config.HistoryWhenClosed = historyWhenClosed;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
int numHistory = this.plugin.Config.NumHistory;
|
|
||||||
if (ImGui.InputInt("Number of previous targeters to keep", ref numHistory)) {
|
|
||||||
numHistory = Math.Max(0, Math.Min(50, numHistory));
|
|
||||||
this.plugin.Config.NumHistory = numHistory;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.EndTabItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.BeginTabItem("Advanced")) {
|
|
||||||
int pollFrequency = this.plugin.Config.PollFrequency;
|
|
||||||
if (ImGui.DragInt("Poll frequency in milliseconds", ref pollFrequency, .1f, 1, 1600)) {
|
|
||||||
this.plugin.Config.PollFrequency = pollFrequency;
|
|
||||||
this.plugin.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.EndTabItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.BeginTabItem("Debug")) {
|
|
||||||
if (ImGui.Button("Log targeting you")) {
|
|
||||||
PlayerCharacter player = this.plugin.Interface.ClientState.LocalPlayer;
|
|
||||||
if (player != null) {
|
|
||||||
// loop over all players looking at the current player
|
|
||||||
var actors = this.plugin.Interface.ClientState.Actors
|
|
||||||
.Where(actor => actor.TargetActorID == player.ActorId && actor is PlayerCharacter)
|
|
||||||
.Select(actor => actor as PlayerCharacter);
|
|
||||||
foreach (PlayerCharacter actor in actors) {
|
|
||||||
PlayerPayload payload = new PlayerPayload(this.plugin.Interface.Data, actor.Name, actor.HomeWorld.Id);
|
|
||||||
Payload[] payloads = { payload };
|
|
||||||
this.plugin.Interface.Framework.Gui.Chat.PrintChat(new XivChatEntry {
|
|
||||||
MessageBytes = new SeString(payloads).Encode()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.Button("Log your target")) {
|
|
||||||
PlayerCharacter target = GetCurrentTarget();
|
|
||||||
|
|
||||||
if (target != null) {
|
|
||||||
PlayerPayload payload = new PlayerPayload(this.plugin.Interface.Data, target.Name, target.HomeWorld.Id);
|
|
||||||
Payload[] payloads = { payload };
|
|
||||||
this.plugin.Interface.Framework.Gui.Chat.PrintChat(new XivChatEntry {
|
|
||||||
MessageBytes = new SeString(payloads).Encode()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.EndTabItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.EndTabBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.End();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ShowMainWindow() {
|
|
||||||
IReadOnlyCollection<Targeter> targeting = this.plugin.Watcher.CurrentTargeters;
|
|
||||||
IReadOnlyCollection<Targeter> previousTargeters = this.plugin.Config.KeepHistory ? this.plugin.Watcher.PreviousTargeters : null;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
if (targeting.Count + (previousTargeters?.Count ?? 0) > 1) {
|
|
||||||
Dictionary<int, Actor> dict = new Dictionary<int, Actor>();
|
|
||||||
foreach (Actor actor in this.plugin.Interface.ClientState.Actors) {
|
|
||||||
if (dict.ContainsKey(actor.ActorId) || actor.ObjectKind != Dalamud.Game.ClientState.Actors.ObjectKind.Player) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
dict.Add(actor.ActorId, actor);
|
|
||||||
}
|
|
||||||
actors = dict;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGuiWindowFlags flags = ImGuiWindowFlags.None;
|
|
||||||
if (!this.plugin.Config.AllowMovement) {
|
|
||||||
flags |= ImGuiWindowFlags.NoMove;
|
|
||||||
}
|
|
||||||
if (!this.plugin.Config.AllowResize) {
|
|
||||||
flags |= ImGuiWindowFlags.NoResize;
|
|
||||||
}
|
|
||||||
ImGui.SetNextWindowSize(new Vector2(290, 195), ImGuiCond.FirstUseEver);
|
|
||||||
if (ImGui.Begin(this.plugin.Name, ref this._wantsOpen, flags)) {
|
|
||||||
ImGui.Text("Targeting you");
|
|
||||||
ImGui.SameLine();
|
|
||||||
// if (this.plugin.Config.OpenExamine) {
|
|
||||||
// HelpMarker("Click to link, Alt-click to examine, or right click to target.");
|
|
||||||
// } else {
|
|
||||||
HelpMarker("Click to link or right click to target.");
|
|
||||||
// }
|
|
||||||
|
|
||||||
float height = ImGui.GetContentRegionAvail().Y;
|
|
||||||
height -= ImGui.GetStyle().ItemSpacing.Y;
|
|
||||||
|
|
||||||
bool anyHovered = false;
|
|
||||||
if (ImGui.ListBoxHeader("##targeting", new Vector2(-1, height))) {
|
|
||||||
// add the two first players for testing
|
|
||||||
//foreach (PlayerCharacter p in this.plugin.Interface.ClientState.Actors
|
|
||||||
// .Where(actor => actor is PlayerCharacter)
|
|
||||||
// .Skip(1)
|
|
||||||
// .Select(actor => actor as PlayerCharacter)
|
|
||||||
// .Take(2)) {
|
|
||||||
// this.AddEntry(new Targeter(p), p, ref anyHovered);
|
|
||||||
//}
|
|
||||||
foreach (Targeter targeter in targeting) {
|
|
||||||
Actor actor = null;
|
|
||||||
actors?.TryGetValue(targeter.ActorId, out actor);
|
|
||||||
this.AddEntry(targeter, actor, ref anyHovered);
|
|
||||||
}
|
|
||||||
if (this.plugin.Config.KeepHistory) {
|
|
||||||
// get a list of the previous targeters that aren't currently targeting
|
|
||||||
var previous = previousTargeters
|
|
||||||
.Where(old => targeting.All(actor => actor.ActorId != old.ActorId))
|
|
||||||
.Take(this.plugin.Config.NumHistory);
|
|
||||||
// add previous targeters to the list
|
|
||||||
foreach (Targeter oldTargeter in previous) {
|
|
||||||
Actor actor = null;
|
|
||||||
actors?.TryGetValue(oldTargeter.ActorId, out actor);
|
|
||||||
this.AddEntry(oldTargeter, actor, ref anyHovered, ImGuiSelectableFlags.Disabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui.ListBoxFooter();
|
|
||||||
}
|
|
||||||
if (this.plugin.Config.FocusTargetOnHover && !anyHovered && this.previousFocus.Get(out Actor previousFocus)) {
|
|
||||||
if (previousFocus == null) {
|
|
||||||
this.plugin.Interface.ClientState.Targets.SetFocusTarget(null);
|
|
||||||
} else {
|
|
||||||
Actor actor = this.plugin.Interface.ClientState.Actors.FirstOrDefault(a => a.ActorId == previousFocus.ActorId);
|
|
||||||
// either target the actor if still present or target nothing
|
|
||||||
this.plugin.Interface.ClientState.Targets.SetFocusTarget(actor);
|
|
||||||
}
|
|
||||||
this.previousFocus = new Optional<Actor>();
|
|
||||||
}
|
|
||||||
ImGui.End();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void HelpMarker(string text) {
|
|
||||||
ImGui.TextDisabled("(?)");
|
|
||||||
if (ImGui.IsItemHovered()) {
|
|
||||||
ImGui.BeginTooltip();
|
|
||||||
ImGui.PushTextWrapPos(ImGui.GetFontSize() * 20f);
|
|
||||||
ImGui.TextUnformatted(text);
|
|
||||||
ImGui.PopTextWrapPos();
|
|
||||||
ImGui.EndTooltip();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddEntry(Targeter targeter, Actor actor, ref bool anyHovered, ImGuiSelectableFlags flags = ImGuiSelectableFlags.None) {
|
|
||||||
ImGui.Selectable(targeter.Name, false, flags);
|
|
||||||
bool hover = ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled);
|
|
||||||
bool left = hover && ImGui.IsMouseClicked(0);
|
|
||||||
bool right = hover && ImGui.IsMouseClicked(1);
|
|
||||||
|
|
||||||
if (actor == null) {
|
|
||||||
actor = this.plugin.Interface.ClientState.Actors
|
|
||||||
.Where(a => a.ActorId == targeter.ActorId)
|
|
||||||
.FirstOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't count as hovered if the actor isn't here (clears focus target when hovering missing actors)
|
|
||||||
if (actor != 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 (left) {
|
|
||||||
if (false && this.plugin.Config.OpenExamine && ImGui.GetIO().KeyAlt) {
|
|
||||||
if (actor != null) {
|
|
||||||
this.plugin.GameFunctions.OpenExamineWindow(actor);
|
|
||||||
} else {
|
|
||||||
Payload[] payloads = {
|
|
||||||
new TextPayload($"[{this.plugin.Name}] "),
|
|
||||||
new PlayerPayload(this.plugin.Interface.Data, targeter.Name, targeter.HomeWorld.Id),
|
|
||||||
new TextPayload(" is not close enough to examine."),
|
|
||||||
};
|
|
||||||
this.plugin.Interface.Framework.Gui.Chat.PrintChat(new XivChatEntry {
|
|
||||||
MessageBytes = new SeString(payloads).Encode(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
PlayerPayload 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(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (right && actor != null) {
|
|
||||||
this.plugin.Interface.ClientState.Targets.SetCurrentTarget(actor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MarkPlayer(PlayerCharacter player, Vector4 colour, float size) {
|
|
||||||
if (player == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.plugin.Interface.Framework.Gui.WorldToScreen(player.Position, out SharpDX.Vector2 screenPos)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.PushClipRect(new Vector2(0, 0), ImGui.GetIO().DisplaySize, false);
|
|
||||||
|
|
||||||
ImGui.GetWindowDrawList().AddCircleFilled(
|
|
||||||
new Vector2(screenPos.X, screenPos.Y),
|
|
||||||
size,
|
|
||||||
ImGui.GetColorU32(colour),
|
|
||||||
100
|
|
||||||
);
|
|
||||||
|
|
||||||
ImGui.PopClipRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
private PlayerCharacter GetCurrentTarget() {
|
|
||||||
PlayerCharacter player = this.plugin.Interface.ClientState.LocalPlayer;
|
|
||||||
if (player == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
int targetId = player.TargetActorID;
|
|
||||||
if (targetId <= 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.plugin.Interface.ClientState.Actors
|
|
||||||
.Where(actor => actor.ActorId == targetId && actor is PlayerCharacter)
|
|
||||||
.Select(actor => actor as PlayerCharacter)
|
|
||||||
.FirstOrDefault();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,571 @@
|
||||||
|
using Dalamud.Game.Chat;
|
||||||
|
using Dalamud.Game.Chat.SeStringHandling;
|
||||||
|
using Dalamud.Game.Chat.SeStringHandling.Payloads;
|
||||||
|
using Dalamud.Game.ClientState;
|
||||||
|
using Dalamud.Game.ClientState.Actors.Types;
|
||||||
|
using ImGuiNET;
|
||||||
|
using NAudio.Wave;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace PeepingTom {
|
||||||
|
internal class PluginUi : IDisposable {
|
||||||
|
private PeepingTomPlugin Plugin { get; }
|
||||||
|
|
||||||
|
private Optional<Actor> PreviousFocus { get; set; } = new Optional<Actor>();
|
||||||
|
|
||||||
|
private bool _wantsOpen;
|
||||||
|
public bool WantsOpen {
|
||||||
|
get => this._wantsOpen;
|
||||||
|
set => this._wantsOpen = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Visible { get; private set; }
|
||||||
|
|
||||||
|
private bool _settingsOpen;
|
||||||
|
public bool SettingsOpen {
|
||||||
|
get => this._settingsOpen;
|
||||||
|
set => this._settingsOpen = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PluginUi(PeepingTomPlugin plugin) {
|
||||||
|
this.Plugin = plugin ?? throw new ArgumentNullException(nameof(plugin), "PeepingTomPlugin cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
this.WantsOpen = false;
|
||||||
|
this.SettingsOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw() {
|
||||||
|
if (this.SettingsOpen) {
|
||||||
|
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];
|
||||||
|
|
||||||
|
// FIXME: this could just be a boolean expression
|
||||||
|
var shouldBeShown = this.WantsOpen;
|
||||||
|
if (inCombat && !this.Plugin.Config.ShowInCombat) {
|
||||||
|
shouldBeShown = false;
|
||||||
|
} else if (inInstance && !this.Plugin.Config.ShowInInstance) {
|
||||||
|
shouldBeShown = false;
|
||||||
|
} else if (inCutscene && !this.Plugin.Config.ShowInCutscenes) {
|
||||||
|
shouldBeShown = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Visible = shouldBeShown;
|
||||||
|
|
||||||
|
if (shouldBeShown) {
|
||||||
|
this.ShowMainWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImGuiWindowFlags flags = ImGuiWindowFlags.NoBackground
|
||||||
|
| ImGuiWindowFlags.NoTitleBar
|
||||||
|
| ImGuiWindowFlags.NoNav
|
||||||
|
| ImGuiWindowFlags.NoNavInputs
|
||||||
|
| ImGuiWindowFlags.NoFocusOnAppearing
|
||||||
|
| ImGuiWindowFlags.NoNavFocus
|
||||||
|
| ImGuiWindowFlags.NoInputs
|
||||||
|
| ImGuiWindowFlags.NoMouseInputs
|
||||||
|
| ImGuiWindowFlags.NoSavedSettings
|
||||||
|
| ImGuiWindowFlags.NoDecoration
|
||||||
|
| ImGuiWindowFlags.NoScrollWithMouse;
|
||||||
|
if (!ImGui.Begin("Peeping Tom targeting indicator dummy window", flags)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.Plugin.Config.MarkTargeted) {
|
||||||
|
this.MarkPlayer(this.GetCurrentTarget(), this.Plugin.Config.TargetedColour, this.Plugin.Config.TargetedSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.Plugin.Config.MarkTargeting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var player = this.Plugin.Interface.ClientState.LocalPlayer;
|
||||||
|
if (player == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var targeting = this.Plugin.Watcher.CurrentTargeters
|
||||||
|
.Select(targeter => this.Plugin.Interface.ClientState.Actors.FirstOrDefault(actor => actor.ActorId == targeter.ActorId))
|
||||||
|
.Where(targeter => targeter != null)
|
||||||
|
.Cast<PlayerCharacter>()
|
||||||
|
.ToArray();
|
||||||
|
foreach (var targeter in targeting) {
|
||||||
|
this.MarkPlayer(targeter, this.Plugin.Config.TargetingColour, this.Plugin.Config.TargetingSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowSettings() {
|
||||||
|
ImGui.SetNextWindowSize(new Vector2(700, 250));
|
||||||
|
if (!ImGui.Begin($"{this.Plugin.Name} settings", ref this._settingsOpen, ImGuiWindowFlags.NoResize)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginTabBar("##settings-tabs")) {
|
||||||
|
if (ImGui.BeginTabItem("Markers")) {
|
||||||
|
var markTargeted = this.Plugin.Config.MarkTargeted;
|
||||||
|
if (ImGui.Checkbox("Mark your target", ref markTargeted)) {
|
||||||
|
this.Plugin.Config.MarkTargeted = markTargeted;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetedColour = this.Plugin.Config.TargetedColour;
|
||||||
|
if (ImGui.ColorEdit4("Target mark colour", ref targetedColour)) {
|
||||||
|
this.Plugin.Config.TargetedColour = targetedColour;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetedSize = this.Plugin.Config.TargetedSize;
|
||||||
|
if (ImGui.DragFloat("Target mark size", ref targetedSize, 0.01f, 0f, 15f)) {
|
||||||
|
targetedSize = Math.Max(0f, targetedSize);
|
||||||
|
this.Plugin.Config.TargetedSize = targetedSize;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Spacing();
|
||||||
|
|
||||||
|
var markTargeting = this.Plugin.Config.MarkTargeting;
|
||||||
|
if (ImGui.Checkbox("Mark targeting you", ref markTargeting)) {
|
||||||
|
this.Plugin.Config.MarkTargeting = markTargeting;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetingColour = this.Plugin.Config.TargetingColour;
|
||||||
|
if (ImGui.ColorEdit4("Targeting mark colour", ref targetingColour)) {
|
||||||
|
this.Plugin.Config.TargetingColour = targetingColour;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetingSize = this.Plugin.Config.TargetingSize;
|
||||||
|
if (ImGui.DragFloat("Targeting mark size", ref targetingSize, 0.01f, 0f, 15f)) {
|
||||||
|
targetingSize = Math.Max(0f, targetingSize);
|
||||||
|
this.Plugin.Config.TargetingSize = targetingSize;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginTabItem("Filters")) {
|
||||||
|
var showParty = this.Plugin.Config.LogParty;
|
||||||
|
if (ImGui.Checkbox("Log party members", ref showParty)) {
|
||||||
|
this.Plugin.Config.LogParty = showParty;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var logAlliance = this.Plugin.Config.LogAlliance;
|
||||||
|
if (ImGui.Checkbox("Log alliance members", ref logAlliance)) {
|
||||||
|
this.Plugin.Config.LogAlliance = logAlliance;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var logInCombat = this.Plugin.Config.LogInCombat;
|
||||||
|
if (ImGui.Checkbox("Log targeters engaged in combat", ref logInCombat)) {
|
||||||
|
this.Plugin.Config.LogInCombat = logInCombat;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var logSelf = this.Plugin.Config.LogSelf;
|
||||||
|
if (ImGui.Checkbox("Log yourself", ref logSelf)) {
|
||||||
|
this.Plugin.Config.LogSelf = logSelf;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginTabItem("Behaviour")) {
|
||||||
|
var focusTarget = this.Plugin.Config.FocusTargetOnHover;
|
||||||
|
if (ImGui.Checkbox("Focus target on hover", ref focusTarget)) {
|
||||||
|
this.Plugin.Config.FocusTargetOnHover = focusTarget;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
// bool openExamine = this.plugin.Config.OpenExamine;
|
||||||
|
// if (ImGui.Checkbox("Open examine window on Alt-click", ref openExamine)) {
|
||||||
|
// this.plugin.Config.OpenExamine = openExamine;
|
||||||
|
// this.plugin.Config.Save();
|
||||||
|
// }
|
||||||
|
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginTabItem("Sound")) {
|
||||||
|
var playSound = this.Plugin.Config.PlaySoundOnTarget;
|
||||||
|
if (ImGui.Checkbox("Play sound when targeted", ref playSound)) {
|
||||||
|
this.Plugin.Config.PlaySoundOnTarget = playSound;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var path = this.Plugin.Config.SoundPath ?? "";
|
||||||
|
if (ImGui.InputText("Path to audio file", ref path, 1_000)) {
|
||||||
|
path = path.Trim();
|
||||||
|
this.Plugin.Config.SoundPath = path.Length == 0 ? null : path;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Text("Leave this blank to use a built-in sound.");
|
||||||
|
|
||||||
|
var volume = this.Plugin.Config.SoundVolume * 100f;
|
||||||
|
if (ImGui.DragFloat("Volume of sound", ref volume, .1f, 0f, 100f, "%.1f%%")) {
|
||||||
|
this.Plugin.Config.SoundVolume = Math.Max(0f, Math.Min(1f, volume / 100f));
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var soundDevice = this.Plugin.Config.SoundDevice;
|
||||||
|
string name;
|
||||||
|
if (soundDevice == -1) {
|
||||||
|
name = "Default";
|
||||||
|
} else if (soundDevice > -1 && soundDevice < WaveOut.DeviceCount) {
|
||||||
|
var caps = WaveOut.GetCapabilities(soundDevice);
|
||||||
|
name = caps.ProductName;
|
||||||
|
} else {
|
||||||
|
name = "Invalid device";
|
||||||
|
}
|
||||||
|
if (ImGui.BeginCombo("Output device", name)) {
|
||||||
|
if (ImGui.Selectable("Default")) {
|
||||||
|
this.Plugin.Config.SoundDevice = -1;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
|
for (var deviceNum = 0; deviceNum < WaveOut.DeviceCount; deviceNum++) {
|
||||||
|
var caps = WaveOut.GetCapabilities(deviceNum);
|
||||||
|
if (!ImGui.Selectable(caps.ProductName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Plugin.Config.SoundDevice = deviceNum;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
var soundCooldown = this.Plugin.Config.SoundCooldown;
|
||||||
|
if (ImGui.DragFloat("Cooldown for sound (seconds)", ref soundCooldown, .01f, 0f, 30f)) {
|
||||||
|
soundCooldown = Math.Max(0f, soundCooldown);
|
||||||
|
this.Plugin.Config.SoundCooldown = soundCooldown;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var playWhenClosed = this.Plugin.Config.PlaySoundWhenClosed;
|
||||||
|
if (ImGui.Checkbox("Play sound when window is closed", ref playWhenClosed)) {
|
||||||
|
this.Plugin.Config.PlaySoundWhenClosed = playWhenClosed;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginTabItem("Window")) {
|
||||||
|
var openOnLogin = this.Plugin.Config.OpenOnLogin;
|
||||||
|
if (ImGui.Checkbox("Open on login", ref openOnLogin)) {
|
||||||
|
this.Plugin.Config.OpenOnLogin = openOnLogin;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var allowMovement = this.Plugin.Config.AllowMovement;
|
||||||
|
if (ImGui.Checkbox("Allow moving the main window", ref allowMovement)) {
|
||||||
|
this.Plugin.Config.AllowMovement = allowMovement;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var allowResizing = this.Plugin.Config.AllowResize;
|
||||||
|
if (ImGui.Checkbox("Allow resizing the main window", ref allowResizing)) {
|
||||||
|
this.Plugin.Config.AllowResize = allowResizing;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Spacing();
|
||||||
|
|
||||||
|
var showInCombat = this.Plugin.Config.ShowInCombat;
|
||||||
|
if (ImGui.Checkbox("Show window while in combat", ref showInCombat)) {
|
||||||
|
this.Plugin.Config.ShowInCombat = showInCombat;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var showInInstance = this.Plugin.Config.ShowInInstance;
|
||||||
|
if (ImGui.Checkbox("Show window while in instance", ref showInInstance)) {
|
||||||
|
this.Plugin.Config.ShowInInstance = showInInstance;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var showInCutscenes = this.Plugin.Config.ShowInCutscenes;
|
||||||
|
if (ImGui.Checkbox("Show window while in cutscenes", ref showInCutscenes)) {
|
||||||
|
this.Plugin.Config.ShowInCutscenes = showInCutscenes;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginTabItem("History")) {
|
||||||
|
var keepHistory = this.Plugin.Config.KeepHistory;
|
||||||
|
if (ImGui.Checkbox("Show previous targeters", ref keepHistory)) {
|
||||||
|
this.Plugin.Config.KeepHistory = keepHistory;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var historyWhenClosed = this.Plugin.Config.HistoryWhenClosed;
|
||||||
|
if (ImGui.Checkbox("Record history when window is closed", ref historyWhenClosed)) {
|
||||||
|
this.Plugin.Config.HistoryWhenClosed = historyWhenClosed;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var numHistory = this.Plugin.Config.NumHistory;
|
||||||
|
if (ImGui.InputInt("Number of previous targeters to keep", ref numHistory)) {
|
||||||
|
numHistory = Math.Max(0, Math.Min(50, numHistory));
|
||||||
|
this.Plugin.Config.NumHistory = numHistory;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginTabItem("Advanced")) {
|
||||||
|
var pollFrequency = this.Plugin.Config.PollFrequency;
|
||||||
|
if (ImGui.DragInt("Poll frequency in milliseconds", ref pollFrequency, .1f, 1, 1600)) {
|
||||||
|
this.Plugin.Config.PollFrequency = pollFrequency;
|
||||||
|
this.Plugin.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginTabItem("Debug")) {
|
||||||
|
if (ImGui.Button("Log targeting you")) {
|
||||||
|
var player = this.Plugin.Interface.ClientState.LocalPlayer;
|
||||||
|
if (player != null) {
|
||||||
|
// loop over all players looking at the current player
|
||||||
|
var actors = this.Plugin.Interface.ClientState.Actors
|
||||||
|
.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);
|
||||||
|
Payload[] payloads = { payload };
|
||||||
|
this.Plugin.Interface.Framework.Gui.Chat.PrintChat(new XivChatEntry {
|
||||||
|
MessageBytes = new SeString(payloads).Encode()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.Button("Log your target")) {
|
||||||
|
var target = this.GetCurrentTarget();
|
||||||
|
|
||||||
|
if (target != null) {
|
||||||
|
var payload = new PlayerPayload(this.Plugin.Interface.Data, target.Name, target.HomeWorld.Id);
|
||||||
|
Payload[] payloads = { payload };
|
||||||
|
this.Plugin.Interface.Framework.Gui.Chat.PrintChat(new XivChatEntry {
|
||||||
|
MessageBytes = new SeString(payloads).Encode()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowMainWindow() {
|
||||||
|
var targeting = this.Plugin.Watcher.CurrentTargeters;
|
||||||
|
var previousTargeters = this.Plugin.Config.KeepHistory ? this.Plugin.Watcher.PreviousTargeters : null;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
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) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dict.Add(actor.ActorId, actor);
|
||||||
|
}
|
||||||
|
actors = dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
var flags = ImGuiWindowFlags.None;
|
||||||
|
if (!this.Plugin.Config.AllowMovement) {
|
||||||
|
flags |= ImGuiWindowFlags.NoMove;
|
||||||
|
}
|
||||||
|
if (!this.Plugin.Config.AllowResize) {
|
||||||
|
flags |= ImGuiWindowFlags.NoResize;
|
||||||
|
}
|
||||||
|
ImGui.SetNextWindowSize(new Vector2(290, 195), ImGuiCond.FirstUseEver);
|
||||||
|
if (!ImGui.Begin(this.Plugin.Name, ref this._wantsOpen, flags)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ImGui.Text("Targeting you");
|
||||||
|
ImGui.SameLine();
|
||||||
|
// if (this.plugin.Config.OpenExamine) {
|
||||||
|
// HelpMarker("Click to link, Alt-click to examine, or right click to target.");
|
||||||
|
// } else {
|
||||||
|
HelpMarker("Click to link or right click to target.");
|
||||||
|
// }
|
||||||
|
|
||||||
|
var height = ImGui.GetContentRegionAvail().Y;
|
||||||
|
height -= ImGui.GetStyle().ItemSpacing.Y;
|
||||||
|
|
||||||
|
var anyHovered = false;
|
||||||
|
if (ImGui.ListBoxHeader("##targeting", new Vector2(-1, height))) {
|
||||||
|
// add the two first players for testing
|
||||||
|
//foreach (PlayerCharacter p in this.plugin.Interface.ClientState.Actors
|
||||||
|
// .Where(actor => actor is PlayerCharacter)
|
||||||
|
// .Skip(1)
|
||||||
|
// .Select(actor => actor as PlayerCharacter)
|
||||||
|
// .Take(2)) {
|
||||||
|
// this.AddEntry(new Targeter(p), p, ref anyHovered);
|
||||||
|
//}
|
||||||
|
foreach (var targeter in targeting) {
|
||||||
|
Actor? actor = null;
|
||||||
|
actors?.TryGetValue(targeter.ActorId, out actor);
|
||||||
|
this.AddEntry(targeter, actor, 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))
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui.ListBoxFooter();
|
||||||
|
}
|
||||||
|
if (this.Plugin.Config.FocusTargetOnHover && !anyHovered && this.PreviousFocus.Get(out var previousFocus)) {
|
||||||
|
if (previousFocus == null) {
|
||||||
|
this.Plugin.Interface.ClientState.Targets.SetFocusTarget(null);
|
||||||
|
} else {
|
||||||
|
var actor = this.Plugin.Interface.ClientState.Actors.FirstOrDefault(a => a.ActorId == previousFocus.ActorId);
|
||||||
|
// either target the actor if still present or target nothing
|
||||||
|
this.Plugin.Interface.ClientState.Targets.SetFocusTarget(actor);
|
||||||
|
}
|
||||||
|
this.PreviousFocus = new Optional<Actor>();
|
||||||
|
}
|
||||||
|
ImGui.End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void HelpMarker(string text) {
|
||||||
|
ImGui.TextDisabled("(?)");
|
||||||
|
if (!ImGui.IsItemHovered()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.BeginTooltip();
|
||||||
|
ImGui.PushTextWrapPos(ImGui.GetFontSize() * 20f);
|
||||||
|
ImGui.TextUnformatted(text);
|
||||||
|
ImGui.PopTextWrapPos();
|
||||||
|
ImGui.EndTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddEntry(Targeter targeter, Actor? actor, ref bool anyHovered, ImGuiSelectableFlags flags = ImGuiSelectableFlags.None) {
|
||||||
|
ImGui.Selectable(targeter.Name, false, flags);
|
||||||
|
var hover = ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled);
|
||||||
|
var left = hover && ImGui.IsMouseClicked(0);
|
||||||
|
var right = hover && ImGui.IsMouseClicked(1);
|
||||||
|
|
||||||
|
actor ??= this.Plugin.Interface.ClientState.Actors
|
||||||
|
.FirstOrDefault(a => a.ActorId == targeter.ActorId);
|
||||||
|
|
||||||
|
// don't count as hovered if the actor isn't here (clears focus target when hovering missing actors)
|
||||||
|
if (actor != 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 (left) {
|
||||||
|
if (false && this.Plugin.Config.OpenExamine && ImGui.GetIO().KeyAlt) {
|
||||||
|
if (actor != null) {
|
||||||
|
this.Plugin.GameFunctions.OpenExamineWindow(actor);
|
||||||
|
} else {
|
||||||
|
Payload[] payloads = {
|
||||||
|
new TextPayload($"[{this.Plugin.Name}] "),
|
||||||
|
new PlayerPayload(this.Plugin.Interface.Data, targeter.Name, targeter.HomeWorld.Id),
|
||||||
|
new TextPayload(" is not close enough to examine."),
|
||||||
|
};
|
||||||
|
this.Plugin.Interface.Framework.Gui.Chat.PrintChat(new XivChatEntry {
|
||||||
|
MessageBytes = new SeString(payloads).Encode(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} 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(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (right && actor != null) {
|
||||||
|
this.Plugin.Interface.ClientState.Targets.SetCurrentTarget(actor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MarkPlayer(Actor? player, Vector4 colour, float size) {
|
||||||
|
if (player == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.Plugin.Interface.Framework.Gui.WorldToScreen(player.Position, out var screenPos)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PushClipRect(new Vector2(0, 0), ImGui.GetIO().DisplaySize, false);
|
||||||
|
|
||||||
|
ImGui.GetWindowDrawList().AddCircleFilled(
|
||||||
|
new Vector2(screenPos.X, screenPos.Y),
|
||||||
|
size,
|
||||||
|
ImGui.GetColorU32(colour),
|
||||||
|
100
|
||||||
|
);
|
||||||
|
|
||||||
|
ImGui.PopClipRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlayerCharacter? GetCurrentTarget() {
|
||||||
|
var player = this.Plugin.Interface.ClientState.LocalPlayer;
|
||||||
|
if (player == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetId = player.TargetActorID;
|
||||||
|
if (targetId <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Plugin.Interface.ClientState.Actors
|
||||||
|
.Where(actor => actor.ActorId == targetId && actor is PlayerCharacter)
|
||||||
|
.Select(actor => actor as PlayerCharacter)
|
||||||
|
.FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,38 +0,0 @@
|
||||||
using System.Resources;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("Peeping Tom")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("")]
|
|
||||||
[assembly: AssemblyProduct("Peeping Tom")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2020")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
|
|
||||||
// Setting ComVisible to false makes the types in this assembly not visible
|
|
||||||
// to COM components. If you need to access a type in this assembly from
|
|
||||||
// COM, set the ComVisible attribute to true on that type.
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
||||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
|
||||||
[assembly: Guid("888f98df-af1d-4852-8411-11b1feefe674")]
|
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
|
||||||
//
|
|
||||||
// Major Version
|
|
||||||
// Minor Version
|
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.5.2")]
|
|
||||||
[assembly: AssemblyFileVersion("1.5.2")]
|
|
||||||
[assembly: NeutralResourcesLanguage("en-GB")]
|
|
|
@ -1,72 +0,0 @@
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// <auto-generated>
|
|
||||||
// This code was generated by a tool.
|
|
||||||
// Runtime Version:4.0.30319.42000
|
|
||||||
//
|
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
|
||||||
// the code is regenerated.
|
|
||||||
// </auto-generated>
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
namespace PeepingTom.Properties {
|
|
||||||
using System;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
|
||||||
/// </summary>
|
|
||||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
|
||||||
// class via a tool like ResGen or Visual Studio.
|
|
||||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
|
||||||
// with the /str option, or rebuild your VS project.
|
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
|
||||||
internal class Resources {
|
|
||||||
|
|
||||||
private static global::System.Resources.ResourceManager resourceMan;
|
|
||||||
|
|
||||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
|
||||||
|
|
||||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
|
||||||
internal Resources() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the cached ResourceManager instance used by this class.
|
|
||||||
/// </summary>
|
|
||||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
|
||||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
|
||||||
get {
|
|
||||||
if (object.ReferenceEquals(resourceMan, null)) {
|
|
||||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PeepingTom.Properties.Resources", typeof(Resources).Assembly);
|
|
||||||
resourceMan = temp;
|
|
||||||
}
|
|
||||||
return resourceMan;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Overrides the current thread's CurrentUICulture property for all
|
|
||||||
/// resource lookups using this strongly typed resource class.
|
|
||||||
/// </summary>
|
|
||||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
|
||||||
internal static global::System.Globalization.CultureInfo Culture {
|
|
||||||
get {
|
|
||||||
return resourceCulture;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
resourceCulture = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized resource of type System.IO.UnmanagedMemoryStream similar to System.IO.MemoryStream.
|
|
||||||
/// </summary>
|
|
||||||
internal static System.IO.UnmanagedMemoryStream Target {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetStream("Target", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,6 +5,7 @@ using Dalamud.Game.ClientState.Actors.Types;
|
||||||
using Dalamud.Game.Internal;
|
using Dalamud.Game.Internal;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using NAudio.Wave;
|
using NAudio.Wave;
|
||||||
|
using Resourcer;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -13,148 +14,148 @@ using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace PeepingTom {
|
namespace PeepingTom {
|
||||||
class TargetWatcher : IDisposable {
|
internal class TargetWatcher : IDisposable {
|
||||||
private readonly PeepingTomPlugin plugin;
|
private PeepingTomPlugin Plugin { get; }
|
||||||
|
|
||||||
private Stopwatch watch = null;
|
private Stopwatch? Watch { get; set; }
|
||||||
private int lastTargetAmount = 0;
|
private int LastTargetAmount { get; set; }
|
||||||
|
|
||||||
private volatile bool stop = false;
|
private volatile bool _stop;
|
||||||
private volatile bool needsUpdate = true;
|
private volatile bool _needsUpdate = true;
|
||||||
private Thread thread;
|
private Thread? Thread { get; set; }
|
||||||
|
|
||||||
private readonly object dataMutex = new object();
|
private readonly object _dataMutex = new object();
|
||||||
private TargetThreadData data;
|
private TargetThreadData? Data { get; set; }
|
||||||
|
|
||||||
|
private readonly Mutex _currentMutex = new Mutex();
|
||||||
|
private Targeter[] Current { get; set; } = Array.Empty<Targeter>();
|
||||||
|
|
||||||
private readonly Mutex currentMutex = new Mutex();
|
|
||||||
private Targeter[] current = Array.Empty<Targeter>();
|
|
||||||
public IReadOnlyCollection<Targeter> CurrentTargeters {
|
public IReadOnlyCollection<Targeter> CurrentTargeters {
|
||||||
get {
|
get {
|
||||||
this.currentMutex.WaitOne();
|
this._currentMutex.WaitOne();
|
||||||
Targeter[] current = this.current.ToArray();
|
var current = this.Current.ToArray();
|
||||||
this.currentMutex.ReleaseMutex();
|
this._currentMutex.ReleaseMutex();
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Mutex previousMutex = new Mutex();
|
private readonly Mutex _previousMutex = new Mutex();
|
||||||
private readonly List<Targeter> previousTargeters = new List<Targeter>();
|
private List<Targeter> Previous { get; set; } = new List<Targeter>();
|
||||||
|
|
||||||
public IReadOnlyCollection<Targeter> PreviousTargeters {
|
public IReadOnlyCollection<Targeter> PreviousTargeters {
|
||||||
get {
|
get {
|
||||||
this.previousMutex.WaitOne();
|
this._previousMutex.WaitOne();
|
||||||
Targeter[] previous = this.previousTargeters.ToArray();
|
var previous = this.Previous.ToArray();
|
||||||
this.previousMutex.ReleaseMutex();
|
this._previousMutex.ReleaseMutex();
|
||||||
return previous;
|
return previous;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TargetWatcher(PeepingTomPlugin plugin) {
|
public TargetWatcher(PeepingTomPlugin plugin) {
|
||||||
this.plugin = plugin ?? throw new ArgumentNullException(nameof(plugin), "PeepingTomPlugin cannot be null");
|
this.Plugin = plugin ?? throw new ArgumentNullException(nameof(plugin), "PeepingTomPlugin cannot be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearPrevious() {
|
public void ClearPrevious() {
|
||||||
this.previousMutex.WaitOne();
|
this._previousMutex.WaitOne();
|
||||||
this.previousTargeters.Clear();
|
this.Previous.Clear();
|
||||||
this.previousMutex.ReleaseMutex();
|
this._previousMutex.ReleaseMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartThread() {
|
public void StartThread() {
|
||||||
this.thread = new Thread(new ThreadStart(() => {
|
this.Thread = new Thread(() => {
|
||||||
while (!this.stop) {
|
while (!this._stop) {
|
||||||
this.Update();
|
this.Update();
|
||||||
this.needsUpdate = true;
|
this._needsUpdate = true;
|
||||||
Thread.Sleep(this.plugin.Config.PollFrequency);
|
Thread.Sleep(this.Plugin.Config.PollFrequency);
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
this.thread.Start();
|
this.Thread.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WaitStopThread() {
|
public void WaitStopThread() {
|
||||||
this.stop = true;
|
this._stop = true;
|
||||||
this.thread?.Join();
|
this.Thread?.Join();
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "delegate")]
|
|
||||||
public void OnFrameworkUpdate(Framework framework) {
|
public void OnFrameworkUpdate(Framework framework) {
|
||||||
if (!this.needsUpdate) {
|
if (!this._needsUpdate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock (this.dataMutex) {
|
lock (this._dataMutex) {
|
||||||
this.data = new TargetThreadData(this.plugin.Interface);
|
this.Data = new TargetThreadData(this.Plugin.Interface);
|
||||||
}
|
}
|
||||||
this.needsUpdate = false;
|
|
||||||
|
this._needsUpdate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Update() {
|
private void Update() {
|
||||||
lock (this.dataMutex) {
|
lock (this._dataMutex) {
|
||||||
if (this.data == null) {
|
var player = this.Data?.LocalPlayer;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayerCharacter player = this.data.localPlayer;
|
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// block until lease
|
// block until lease
|
||||||
this.currentMutex.WaitOne();
|
this._currentMutex.WaitOne();
|
||||||
|
|
||||||
// get targeters and set a copy so we can release the mutex faster
|
// get targeters and set a copy so we can release the mutex faster
|
||||||
Targeter[] current = this.GetTargeting(this.data.actors, player);
|
var current = this.GetTargeting(this.Data!.Actors, player);
|
||||||
this.current = (Targeter[])current.Clone();
|
this.Current = (Targeter[]) current.Clone();
|
||||||
|
|
||||||
// release
|
// release
|
||||||
this.currentMutex.ReleaseMutex();
|
this._currentMutex.ReleaseMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.HandleHistory(current);
|
this.HandleHistory(this.Current);
|
||||||
|
|
||||||
// play sound if necessary
|
// play sound if necessary
|
||||||
if (this.CanPlaySound()) {
|
if (this.CanPlaySound()) {
|
||||||
this.watch.Restart();
|
this.Watch?.Restart();
|
||||||
this.PlaySound();
|
this.PlaySound();
|
||||||
}
|
}
|
||||||
this.lastTargetAmount = this.current.Length;
|
|
||||||
|
this.LastTargetAmount = this.Current.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleHistory(Targeter[] targeting) {
|
private void HandleHistory(Targeter[] targeting) {
|
||||||
if (!this.plugin.Config.KeepHistory || (!this.plugin.Config.HistoryWhenClosed && !this.plugin.Ui.Visible)) {
|
if (!this.Plugin.Config.KeepHistory || (!this.Plugin.Config.HistoryWhenClosed && !this.Plugin.Ui.Visible)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.previousMutex.WaitOne();
|
this._previousMutex.WaitOne();
|
||||||
|
|
||||||
foreach (Targeter targeter in targeting) {
|
foreach (var targeter in targeting) {
|
||||||
// add the targeter to the previous list
|
// add the targeter to the previous list
|
||||||
if (this.previousTargeters.Any(old => old.ActorId == targeter.ActorId)) {
|
if (this.Previous.Any(old => old.ActorId == targeter.ActorId)) {
|
||||||
this.previousTargeters.RemoveAll(old => old.ActorId == targeter.ActorId);
|
this.Previous.RemoveAll(old => old.ActorId == targeter.ActorId);
|
||||||
}
|
}
|
||||||
this.previousTargeters.Insert(0, targeter);
|
|
||||||
|
this.Previous.Insert(0, targeter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// only keep the configured number of previous targeters (ignoring ones that are currently targeting)
|
// only keep the configured number of previous targeters (ignoring ones that are currently targeting)
|
||||||
while (this.previousTargeters.Where(old => targeting.All(actor => actor.ActorId != old.ActorId)).Count() > this.plugin.Config.NumHistory) {
|
while (this.Previous.Count(old => targeting.All(actor => actor.ActorId != old.ActorId)) > this.Plugin.Config.NumHistory) {
|
||||||
this.previousTargeters.RemoveAt(this.previousTargeters.Count - 1);
|
this.Previous.RemoveAt(this.Previous.Count - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.previousMutex.ReleaseMutex();
|
this._previousMutex.ReleaseMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Targeter[] GetTargeting(Actor[] actors, Actor player) {
|
private Targeter[] GetTargeting(IEnumerable<Actor> actors, Actor player) {
|
||||||
return actors
|
return actors
|
||||||
.Where(actor => actor.TargetActorID == player.ActorId && actor is PlayerCharacter)
|
.Where(actor => actor.TargetActorID == player.ActorId && actor is PlayerCharacter)
|
||||||
.Select(actor => actor as PlayerCharacter)
|
.Cast<PlayerCharacter>()
|
||||||
.Where(actor => this.plugin.Config.LogParty || !InParty(actor))
|
.Where(actor => this.Plugin.Config.LogParty || !InParty(actor))
|
||||||
.Where(actor => this.plugin.Config.LogAlliance || !InAlliance(actor))
|
.Where(actor => this.Plugin.Config.LogAlliance || !InAlliance(actor))
|
||||||
.Where(actor => this.plugin.Config.LogInCombat || !InCombat(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.ActorId != player.ActorId)
|
||||||
.Select(actor => new Targeter(actor))
|
.Select(actor => new Targeter(actor))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte GetStatus(Actor actor) {
|
private static byte GetStatus(Actor actor) {
|
||||||
IntPtr statusPtr = actor.Address + 0x1906; // updated 5.3
|
var statusPtr = actor.Address + 0x1906; // updated 5.3
|
||||||
return Marshal.ReadByte(statusPtr);
|
return Marshal.ReadByte(statusPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,40 +166,40 @@ namespace PeepingTom {
|
||||||
private static bool InAlliance(Actor actor) => (GetStatus(actor) & 32) > 0;
|
private static bool InAlliance(Actor actor) => (GetStatus(actor) & 32) > 0;
|
||||||
|
|
||||||
private bool CanPlaySound() {
|
private bool CanPlaySound() {
|
||||||
if (!this.plugin.Config.PlaySoundOnTarget) {
|
if (!this.Plugin.Config.PlaySoundOnTarget) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.current.Length <= this.lastTargetAmount) {
|
if (this.Current.Length <= this.LastTargetAmount) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.plugin.Config.PlaySoundWhenClosed && !this.plugin.Ui.Visible) {
|
if (!this.Plugin.Config.PlaySoundWhenClosed && !this.Plugin.Ui.Visible) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.watch == null) {
|
if (this.Watch == null) {
|
||||||
this.watch = new Stopwatch();
|
this.Watch = new Stopwatch();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double secs = this.watch.Elapsed.TotalSeconds;
|
var secs = this.Watch.Elapsed.TotalSeconds;
|
||||||
return secs >= this.plugin.Config.SoundCooldown;
|
return secs >= this.Plugin.Config.SoundCooldown;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PlaySound() {
|
private void PlaySound() {
|
||||||
int soundDevice = this.plugin.Config.SoundDevice;
|
var soundDevice = this.Plugin.Config.SoundDevice;
|
||||||
if (soundDevice < -1 || soundDevice > WaveOut.DeviceCount) {
|
if (soundDevice < -1 || soundDevice > WaveOut.DeviceCount) {
|
||||||
soundDevice = -1;
|
soundDevice = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
new Thread(new ThreadStart(() => {
|
new Thread(() => {
|
||||||
WaveStream reader;
|
WaveStream reader;
|
||||||
try {
|
try {
|
||||||
if (this.plugin.Config.SoundPath == null) {
|
if (this.Plugin.Config.SoundPath == null) {
|
||||||
reader = new WaveFileReader(Properties.Resources.Target);
|
reader = new WaveFileReader(Resource.AsStream("Resources/target.wav"));
|
||||||
} else {
|
} else {
|
||||||
reader = new AudioFileReader(this.plugin.Config.SoundPath);
|
reader = new AudioFileReader(this.Plugin.Config.SoundPath);
|
||||||
}
|
}
|
||||||
#pragma warning disable CA1031 // Do not catch general exception types
|
#pragma warning disable CA1031 // Do not catch general exception types
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -207,9 +208,7 @@ namespace PeepingTom {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaveChannel32 channel = new WaveChannel32(reader) {
|
WaveChannel32 channel = new WaveChannel32(reader) {Volume = this.Plugin.Config.SoundVolume,};
|
||||||
Volume = this.plugin.Config.SoundVolume,
|
|
||||||
};
|
|
||||||
|
|
||||||
using (reader) {
|
using (reader) {
|
||||||
using (var output = new WaveOutEvent() {DeviceNumber = soundDevice}) {
|
using (var output = new WaveOutEvent() {DeviceNumber = soundDevice}) {
|
||||||
|
@ -221,30 +220,29 @@ namespace PeepingTom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})).Start();
|
}).Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SendError(string message) {
|
private void SendError(string message) {
|
||||||
Payload[] payloads = { new TextPayload($"[{this.plugin.Name}] {message}") };
|
Payload[] payloads = {
|
||||||
this.plugin.Interface.Framework.Gui.Chat.PrintChat(new XivChatEntry {
|
new TextPayload($"[{this.Plugin.Name}] {message}"),
|
||||||
MessageBytes = new SeString(payloads).Encode(),
|
};
|
||||||
Type = XivChatType.ErrorMessage,
|
this.Plugin.Interface.Framework.Gui.Chat.PrintChat(new XivChatEntry {MessageBytes = new SeString(payloads).Encode(), Type = XivChatType.ErrorMessage,});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose() {
|
public void Dispose() {
|
||||||
this.currentMutex.Dispose();
|
this._currentMutex.Dispose();
|
||||||
this.previousMutex.Dispose();
|
this._previousMutex.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TargetThreadData {
|
internal class TargetThreadData {
|
||||||
public PlayerCharacter localPlayer;
|
public PlayerCharacter LocalPlayer { get; }
|
||||||
public Actor[] actors;
|
public Actor[] Actors { get; }
|
||||||
|
|
||||||
public TargetThreadData(DalamudPluginInterface pi) {
|
public TargetThreadData(DalamudPluginInterface pi) {
|
||||||
this.localPlayer = pi.ClientState.LocalPlayer;
|
this.LocalPlayer = pi.ClientState.LocalPlayer;
|
||||||
this.actors = pi.ClientState.Actors.ToArray();
|
this.Actors = pi.ClientState.Actors.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace PeepingTom {
|
||||||
this.ActorId = character.ActorId;
|
this.ActorId = character.ActorId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerCharacter GetPlayerCharacter(DalamudPluginInterface pi) {
|
public PlayerCharacter? GetPlayerCharacter(DalamudPluginInterface pi) {
|
||||||
if (pi == null) {
|
if (pi == null) {
|
||||||
throw new ArgumentNullException(nameof(pi), "DalamudPluginInterface cannot be null");
|
throw new ArgumentNullException(nameof(pi), "DalamudPluginInterface cannot be null");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
namespace PeepingTom {
|
namespace PeepingTom {
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1716:Identifiers should not match keywords")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1716:Identifiers should not match keywords")]
|
||||||
public class Optional<T> {
|
public class Optional<T> where T : class {
|
||||||
public bool Present { get; private set; }
|
public bool Present { get; }
|
||||||
private readonly T value;
|
private readonly T? _value;
|
||||||
|
|
||||||
public Optional(T value) {
|
public Optional(T? value) {
|
||||||
this.value = value;
|
this._value = value;
|
||||||
this.Present = true;
|
this.Present = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@
|
||||||
this.Present = false;
|
this.Present = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Get(out T value) {
|
public bool Get(out T? value) {
|
||||||
value = this.value;
|
value = this._value;
|
||||||
return this.Present;
|
return this.Present;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<packages>
|
|
||||||
<package id="Microsoft.CodeAnalysis.FxCopAnalyzers" version="2.9.6" targetFramework="net48" developmentDependency="true" />
|
|
||||||
<package id="Microsoft.CodeAnalysis.VersionCheckAnalyzer" version="2.9.6" targetFramework="net48" developmentDependency="true" />
|
|
||||||
<package id="Microsoft.CodeQuality.Analyzers" version="2.9.6" targetFramework="net48" developmentDependency="true" />
|
|
||||||
<package id="Microsoft.NetCore.Analyzers" version="2.9.6" targetFramework="net48" developmentDependency="true" />
|
|
||||||
<package id="Microsoft.NetFramework.Analyzers" version="2.9.6" targetFramework="net48" developmentDependency="true" />
|
|
||||||
<package id="NAudio" version="1.10.0" targetFramework="net48" />
|
|
||||||
</packages>
|
|
Loading…
Reference in New Issue