mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
Merge pull request #1440 from goatcorp/v9
This commit is contained in:
commit
b2f233192f
251 changed files with 4662 additions and 6037 deletions
|
|
@ -35,7 +35,7 @@ dotnet_naming_rule.private_instance_fields_rule.severity = warning
|
|||
dotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style
|
||||
dotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols
|
||||
dotnet_naming_rule.private_static_fields_rule.severity = warning
|
||||
dotnet_naming_rule.private_static_fields_rule.style = upper_camel_case_style
|
||||
dotnet_naming_rule.private_static_fields_rule.style = lower_camel_case_style
|
||||
dotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols
|
||||
dotnet_naming_rule.private_static_readonly_rule.severity = warning
|
||||
dotnet_naming_rule.private_static_readonly_rule.style = upper_camel_case_style
|
||||
|
|
@ -57,12 +57,12 @@ dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static
|
|||
dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private
|
||||
dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field
|
||||
dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static,readonly
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators =always_for_clarity:suggestion
|
||||
dotnet_style_parentheses_in_other_binary_operators =always_for_clarity:suggestion
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:suggestion
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion
|
||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
|
||||
dotnet_style_parentheses_in_other_operators=always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_operators = always_for_clarity:silent
|
||||
dotnet_style_object_initializer = false
|
||||
dotnet_style_qualification_for_event = true:suggestion
|
||||
dotnet_style_qualification_for_field = true:suggestion
|
||||
|
|
@ -78,7 +78,7 @@ csharp_space_before_comma = false
|
|||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_after_comma = true
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = none
|
||||
|
|
@ -101,7 +101,7 @@ resharper_braces_for_ifelse = required_for_multiline
|
|||
resharper_can_use_global_alias = false
|
||||
resharper_csharp_align_multiline_parameter = true
|
||||
resharper_csharp_align_multiple_declaration = true
|
||||
resharper_csharp_empty_block_style = together_same_line
|
||||
resharper_csharp_empty_block_style = multiline
|
||||
resharper_csharp_int_align_comments = true
|
||||
resharper_csharp_new_line_before_while = true
|
||||
resharper_csharp_wrap_after_declaration_lpar = true
|
||||
|
|
@ -133,13 +133,13 @@ resharper_suggest_var_or_type_built_in_types_highlighting = hint
|
|||
resharper_suggest_var_or_type_elsewhere_highlighting = hint
|
||||
resharper_suggest_var_or_type_simple_types_highlighting = hint
|
||||
resharper_unused_auto_property_accessor_global_highlighting = none
|
||||
csharp_style_deconstructed_variable_declaration=true:silent
|
||||
csharp_style_deconstructed_variable_declaration = true:silent
|
||||
|
||||
[*.{appxmanifest,asax,ascx,aspx,axaml,axml,build,c,c++,cc,cginc,compute,config,cp,cpp,cs,cshtml,csproj,css,cu,cuh,cxx,dbml,discomap,dtd,h,hh,hlsl,hlsli,hlslinc,hpp,htm,html,hxx,inc,inl,ino,ipp,js,json,jsproj,jsx,lsproj,master,mpp,mq4,mq5,mqh,njsproj,nuspec,paml,proj,props,proto,razor,resjson,resw,resx,skin,StyleCop,targets,tasks,tpp,ts,tsx,usf,ush,vb,vbproj,xaml,xamlx,xml,xoml,xsd}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
dotnet_style_parentheses_in_other_operators=always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_operators = always_for_clarity:silent
|
||||
|
||||
[*.{yaml,yml}]
|
||||
indent_style = space
|
||||
|
|
|
|||
|
|
@ -133,8 +133,8 @@ DWORD WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
|
|||
// ============================== VEH ======================================== //
|
||||
|
||||
logging::I("Initializing VEH...");
|
||||
if (utils::is_running_on_linux()) {
|
||||
logging::I("=> VEH was disabled, running on linux");
|
||||
if (utils::is_running_on_wine()) {
|
||||
logging::I("=> VEH was disabled, running on wine");
|
||||
} else if (g_startInfo.BootVehEnabled) {
|
||||
if (veh::add_handler(g_startInfo.BootVehFull, g_startInfo.WorkingDirectory))
|
||||
logging::I("=> Done!");
|
||||
|
|
|
|||
|
|
@ -578,7 +578,7 @@ std::vector<std::string> utils::get_env_list(const wchar_t* pcszName) {
|
|||
return res;
|
||||
}
|
||||
|
||||
bool utils::is_running_on_linux() {
|
||||
bool utils::is_running_on_wine() {
|
||||
if (get_env<bool>(L"XL_WINEONLINUX"))
|
||||
return true;
|
||||
HMODULE hntdll = GetModuleHandleW(L"ntdll.dll");
|
||||
|
|
@ -588,6 +588,10 @@ bool utils::is_running_on_linux() {
|
|||
return true;
|
||||
if (GetProcAddress(hntdll, "wine_get_host_version"))
|
||||
return true;
|
||||
if (GetProcAddress(hntdll, "wine_server_call"))
|
||||
return true;
|
||||
if (GetProcAddress(hntdll, "wine_unix_to_nt_file_name"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ namespace utils {
|
|||
return get_env_list<T>(unicode::convert<std::wstring>(pcszName).c_str());
|
||||
}
|
||||
|
||||
bool is_running_on_linux();
|
||||
bool is_running_on_wine();
|
||||
|
||||
std::filesystem::path get_module_path(HMODULE hModule);
|
||||
|
||||
|
|
|
|||
27
Dalamud.Common/ClientLanguage.cs
Normal file
27
Dalamud.Common/ClientLanguage.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
namespace Dalamud.Common;
|
||||
|
||||
/// <summary>
|
||||
/// Enum describing the language the game loads in.
|
||||
/// </summary>
|
||||
public enum ClientLanguage
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicating a Japanese game client.
|
||||
/// </summary>
|
||||
Japanese,
|
||||
|
||||
/// <summary>
|
||||
/// Indicating an English game client.
|
||||
/// </summary>
|
||||
English,
|
||||
|
||||
/// <summary>
|
||||
/// Indicating a German game client.
|
||||
/// </summary>
|
||||
German,
|
||||
|
||||
/// <summary>
|
||||
/// Indicating a French game client.
|
||||
/// </summary>
|
||||
French,
|
||||
}
|
||||
13
Dalamud.Common/Dalamud.Common.csproj
Normal file
13
Dalamud.Common/Dalamud.Common.csproj
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -1,16 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Common.Game;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud;
|
||||
namespace Dalamud.Common;
|
||||
|
||||
/// <summary>
|
||||
/// Struct containing information needed to initialize Dalamud.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public record DalamudStartInfo : IServiceType
|
||||
public record DalamudStartInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DalamudStartInfo"/> class.
|
||||
|
|
@ -96,7 +93,7 @@ public record DalamudStartInfo : IServiceType
|
|||
/// <summary>
|
||||
/// Gets or sets troubleshooting information to attach when generating a tspack file.
|
||||
/// </summary>
|
||||
public string TroubleshootingPackData { get; set; }
|
||||
public string? TroubleshootingPackData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that specifies how much to wait before a new Dalamud session.
|
||||
|
|
@ -1,11 +1,9 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud.Game;
|
||||
namespace Dalamud.Common.Game;
|
||||
|
||||
/// <summary>
|
||||
/// A GameVersion object contains give hierarchical numeric components: year, month,
|
||||
|
|
@ -168,14 +166,14 @@ public sealed class GameVersion : ICloneable, IComparable, IComparable<GameVersi
|
|||
return Parse(ver);
|
||||
}
|
||||
|
||||
public static bool operator ==(GameVersion v1, GameVersion v2)
|
||||
public static bool operator ==(GameVersion? v1, GameVersion? v2)
|
||||
{
|
||||
if (v1 is null)
|
||||
{
|
||||
return v2 is null;
|
||||
}
|
||||
|
||||
return v1.Equals(v2);
|
||||
return v2 is not null && v1.Equals(v2);
|
||||
}
|
||||
|
||||
public static bool operator !=(GameVersion v1, GameVersion v2)
|
||||
|
|
@ -290,7 +288,7 @@ public sealed class GameVersion : ICloneable, IComparable, IComparable<GameVersi
|
|||
}
|
||||
catch
|
||||
{
|
||||
result = null;
|
||||
result = null!;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -299,7 +297,7 @@ public sealed class GameVersion : ICloneable, IComparable, IComparable<GameVersi
|
|||
public object Clone() => new GameVersion(this.Year, this.Month, this.Day, this.Major, this.Minor);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int CompareTo(object obj)
|
||||
public int CompareTo(object? obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return 1;
|
||||
|
|
@ -315,7 +313,7 @@ public sealed class GameVersion : ICloneable, IComparable, IComparable<GameVersi
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int CompareTo(GameVersion value)
|
||||
public int CompareTo(GameVersion? value)
|
||||
{
|
||||
if (value == null)
|
||||
return 1;
|
||||
|
|
@ -348,7 +346,7 @@ public sealed class GameVersion : ICloneable, IComparable, IComparable<GameVersi
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is not GameVersion value)
|
||||
return false;
|
||||
|
|
@ -357,7 +355,7 @@ public sealed class GameVersion : ICloneable, IComparable, IComparable<GameVersi
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(GameVersion value)
|
||||
public bool Equals(GameVersion? value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
using System;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud.Game;
|
||||
namespace Dalamud.Common.Game;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="GameVersion"/> to and from a string (e.g. <c>"2010.01.01.1234.5678"</c>).
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Lumina" Version="3.10.2" />
|
||||
<PackageReference Include="Lumina" Version="3.11.0" />
|
||||
<PackageReference Include="Lumina.Excel" Version="6.4.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.333">
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ using System;
|
|||
using System.IO;
|
||||
|
||||
using Dalamud.Configuration.Internal;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.Command;
|
||||
using Dalamud.Interface.Windowing;
|
||||
using Dalamud.Logging;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
|
|
@ -39,9 +39,6 @@ namespace Dalamud.CorePlugin
|
|||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Dalamud.CorePlugin";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
@ -52,37 +49,39 @@ namespace Dalamud.CorePlugin
|
|||
private readonly WindowSystem windowSystem = new("Dalamud.CorePlugin");
|
||||
private Localization localization;
|
||||
|
||||
private IPluginLog pluginLog;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginImpl"/> class.
|
||||
/// </summary>
|
||||
/// <param name="pluginInterface">Dalamud plugin interface.</param>
|
||||
/// <param name="log">Logging service.</param>
|
||||
public PluginImpl(DalamudPluginInterface pluginInterface, IPluginLog log)
|
||||
public PluginImpl(DalamudPluginInterface pluginInterface, IPluginLog log, ISigScanner scanner)
|
||||
{
|
||||
try
|
||||
{
|
||||
// this.InitLoc();
|
||||
this.Interface = pluginInterface;
|
||||
this.pluginLog = log;
|
||||
|
||||
this.windowSystem.AddWindow(new PluginWindow());
|
||||
|
||||
this.pluginLog.Information(scanner.ToString());
|
||||
|
||||
this.Interface.UiBuilder.Draw += this.OnDraw;
|
||||
this.Interface.UiBuilder.OpenConfigUi += this.OnOpenConfigUi;
|
||||
this.Interface.UiBuilder.OpenMainUi += this.OnOpenMainUi;
|
||||
|
||||
Service<CommandManager>.Get().AddHandler("/coreplug", new(this.OnCommand) { HelpMessage = $"Access the {this.Name} plugin." });
|
||||
Service<CommandManager>.Get().AddHandler("/coreplug", new(this.OnCommand) { HelpMessage = "Access the plugin." });
|
||||
|
||||
log.Information("CorePlugin ctor!");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginLog.Error(ex, "kaboom");
|
||||
log.Error(ex, "kaboom");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Dalamud.CorePlugin";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin interface.
|
||||
/// </summary>
|
||||
|
|
@ -130,13 +129,13 @@ namespace Dalamud.CorePlugin
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginLog.Error(ex, "Boom");
|
||||
this.pluginLog.Error(ex, "Boom");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCommand(string command, string args)
|
||||
{
|
||||
PluginLog.Information("Command called!");
|
||||
this.pluginLog.Information("Command called!");
|
||||
|
||||
// this.window.IsOpen = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,12 +81,6 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- This prevents us from having to include Dalamud itself as a dependency -->
|
||||
<!-- If the files move just update the paths here -->
|
||||
<Compile Include="..\Dalamud\ClientLanguage.cs" Link="Included\%(Filename)%(Extension)" />
|
||||
<Compile Include="..\Dalamud\IServiceType.cs" Link="Included\%(Filename)%(Extension)" />
|
||||
<Compile Include="..\Dalamud\DalamudStartInfo.cs" Link="Included\%(Filename)%(Extension)" />
|
||||
<Compile Include="..\Dalamud\Game\GameVersion.cs" Link="Included\Game\%(Filename)%(Extension)" />
|
||||
<Compile Include="..\Dalamud\Game\GameVersionConverter.cs" Link="Included\Game\%(Filename)%(Extension)" />
|
||||
<ProjectReference Include="..\Dalamud.Common\Dalamud.Common.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ using System.Runtime.InteropServices;
|
|||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Common;
|
||||
using Dalamud.Common.Game;
|
||||
using Newtonsoft.Json;
|
||||
using Reloaded.Memory.Buffers;
|
||||
using Serilog;
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Platforms>x64;AnyCPU</Platforms>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<RootNamespace>Dalamud.Interface</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\lib\ImGuiScene\deps\ImGui.NET\src\ImGui.NET-472\ImGui.NET-472.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
using Dalamud.Interface.Raii;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface;
|
||||
|
||||
public static class ImGuiTable
|
||||
{
|
||||
// Draw a simple table with the given data using the drawRow action.
|
||||
// Headers and thus columns and column count are defined by columnTitles.
|
||||
public static void DrawTable<T>(string label, IEnumerable<T> data, Action<T> drawRow, ImGuiTableFlags flags = ImGuiTableFlags.None,
|
||||
params string[] columnTitles)
|
||||
{
|
||||
if (columnTitles.Length == 0)
|
||||
return;
|
||||
|
||||
using var table = ImRaii.Table(label, columnTitles.Length, flags);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
foreach (var title in columnTitles)
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableHeader(title);
|
||||
}
|
||||
|
||||
foreach (var datum in data)
|
||||
{
|
||||
ImGui.TableNextRow();
|
||||
drawRow(datum);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw a simple table with the given data using the drawRow action inside a collapsing header.
|
||||
// Headers and thus columns and column count are defined by columnTitles.
|
||||
public static void DrawTabbedTable<T>(string label, IEnumerable<T> data, Action<T> drawRow, ImGuiTableFlags flags = ImGuiTableFlags.None,
|
||||
params string[] columnTitles)
|
||||
{
|
||||
if (ImGui.CollapsingHeader(label))
|
||||
DrawTable($"{label}##Table", data, drawRow, flags, columnTitles);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
namespace Dalamud.Interface;
|
||||
|
||||
public static class InterfaceHelpers
|
||||
{
|
||||
public static float GlobalScale = 1.0f;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
using Dalamud.Game;
|
||||
using Dalamud.Common.Game;
|
||||
using Xunit;
|
||||
|
||||
namespace Dalamud.Test.Game
|
||||
|
|
|
|||
26
Dalamud.sln
26
Dalamud.sln
|
|
@ -38,7 +38,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFXIVClientStructs.InteropS
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DalamudCrashHandler", "DalamudCrashHandler\DalamudCrashHandler.vcxproj", "{317A264C-920B-44A1-8A34-F3A6827B0705}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dalamud.Interface", "Dalamud.Interface\Dalamud.Interface.csproj", "{757C997D-AA58-4241-8299-243C56514917}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dalamud.Common", "Dalamud.Common\Dalamud.Common.csproj", "{F21B13D2-D7D0-4456-B70F-3F8D695064E2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
|
@ -204,18 +204,18 @@ Global
|
|||
{317A264C-920B-44A1-8A34-F3A6827B0705}.Release|x64.Build.0 = Release|x64
|
||||
{317A264C-920B-44A1-8A34-F3A6827B0705}.Release|x86.ActiveCfg = Release|x64
|
||||
{317A264C-920B-44A1-8A34-F3A6827B0705}.Release|x86.Build.0 = Release|x64
|
||||
{757C997D-AA58-4241-8299-243C56514917}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{757C997D-AA58-4241-8299-243C56514917}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{757C997D-AA58-4241-8299-243C56514917}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{757C997D-AA58-4241-8299-243C56514917}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{757C997D-AA58-4241-8299-243C56514917}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{757C997D-AA58-4241-8299-243C56514917}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{757C997D-AA58-4241-8299-243C56514917}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{757C997D-AA58-4241-8299-243C56514917}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{757C997D-AA58-4241-8299-243C56514917}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{757C997D-AA58-4241-8299-243C56514917}.Release|x64.Build.0 = Release|Any CPU
|
||||
{757C997D-AA58-4241-8299-243C56514917}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{757C997D-AA58-4241-8299-243C56514917}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F21B13D2-D7D0-4456-B70F-3F8D695064E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F21B13D2-D7D0-4456-B70F-3F8D695064E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F21B13D2-D7D0-4456-B70F-3F8D695064E2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F21B13D2-D7D0-4456-B70F-3F8D695064E2}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F21B13D2-D7D0-4456-B70F-3F8D695064E2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F21B13D2-D7D0-4456-B70F-3F8D695064E2}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F21B13D2-D7D0-4456-B70F-3F8D695064E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F21B13D2-D7D0-4456-B70F-3F8D695064E2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F21B13D2-D7D0-4456-B70F-3F8D695064E2}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F21B13D2-D7D0-4456-B70F-3F8D695064E2}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F21B13D2-D7D0-4456-B70F-3F8D695064E2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F21B13D2-D7D0-4456-B70F-3F8D695064E2}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
namespace Dalamud;
|
||||
|
||||
// TODO(v10): Delete this, and use Dalamud.Common.ClientLanguage instead for everything.
|
||||
|
||||
/// <summary>
|
||||
/// Enum describing the language the game loads in.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
|
@ -6,7 +5,9 @@ using System.Linq;
|
|||
|
||||
using Dalamud.Game.Text;
|
||||
using Dalamud.Interface.Style;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Internal.Profiles;
|
||||
using Dalamud.Storage;
|
||||
using Dalamud.Utility;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
|
|
@ -18,7 +19,11 @@ namespace Dalamud.Configuration.Internal;
|
|||
/// Class containing Dalamud settings.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal sealed class DalamudConfiguration : IServiceType
|
||||
[ServiceManager.Service]
|
||||
#pragma warning disable SA1015
|
||||
[InherentDependency<ReliableFileStorage>] // We must still have this when unloading
|
||||
#pragma warning restore SA1015
|
||||
internal sealed class DalamudConfiguration : IServiceType, IDisposable
|
||||
{
|
||||
private static readonly JsonSerializerSettings SerializerSettings = new()
|
||||
{
|
||||
|
|
@ -422,23 +427,37 @@ internal sealed class DalamudConfiguration : IServiceType
|
|||
/// <summary>
|
||||
/// Load a configuration from the provided path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to load the configuration file from.</param>
|
||||
/// <param name="path">Path to read from.</param>
|
||||
/// <param name="fs">File storage.</param>
|
||||
/// <returns>The deserialized configuration file.</returns>
|
||||
public static DalamudConfiguration Load(string path)
|
||||
public static DalamudConfiguration Load(string path, ReliableFileStorage fs)
|
||||
{
|
||||
DalamudConfiguration deserialized = null;
|
||||
|
||||
try
|
||||
{
|
||||
deserialized = JsonConvert.DeserializeObject<DalamudConfiguration>(File.ReadAllText(path), SerializerSettings);
|
||||
fs.ReadAllText(path, text =>
|
||||
{
|
||||
deserialized =
|
||||
JsonConvert.DeserializeObject<DalamudConfiguration>(text, SerializerSettings);
|
||||
|
||||
// If this reads as null, the file was empty, that's no good
|
||||
if (deserialized == null)
|
||||
throw new Exception("Read config was null.");
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
Log.Warning(ex, "Failed to load DalamudConfiguration at {0}", path);
|
||||
// ignored
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "Could not load DalamudConfiguration at {Path}, creating new", path);
|
||||
}
|
||||
|
||||
deserialized ??= new DalamudConfiguration();
|
||||
deserialized.configPath = path;
|
||||
|
||||
|
||||
return deserialized;
|
||||
}
|
||||
|
||||
|
|
@ -457,6 +476,13 @@ internal sealed class DalamudConfiguration : IServiceType
|
|||
{
|
||||
this.Save();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
// Make sure that we save, if a save is queued while we are shutting down
|
||||
this.Update();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the file, if needed. Only needs to be done once a frame.
|
||||
|
|
@ -476,7 +502,8 @@ internal sealed class DalamudConfiguration : IServiceType
|
|||
{
|
||||
ThreadSafety.AssertMainThread();
|
||||
|
||||
Util.WriteAllTextSafe(this.configPath, JsonConvert.SerializeObject(this, SerializerSettings));
|
||||
Service<ReliableFileStorage>.Get().WriteAllText(
|
||||
this.configPath, JsonConvert.SerializeObject(this, SerializerSettings));
|
||||
this.DalamudConfigurationSaved?.Invoke(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using System.IO;
|
||||
|
||||
using Dalamud.Utility;
|
||||
using Dalamud.Storage;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud.Configuration;
|
||||
|
|
@ -31,24 +31,39 @@ public sealed class PluginConfigurations
|
|||
/// </summary>
|
||||
/// <param name="config">Plugin configuration.</param>
|
||||
/// <param name="pluginName">Plugin name.</param>
|
||||
public void Save(IPluginConfiguration config, string pluginName)
|
||||
/// <param name="workingPluginId">WorkingPluginId of the plugin.</param>
|
||||
public void Save(IPluginConfiguration config, string pluginName, Guid workingPluginId)
|
||||
{
|
||||
Util.WriteAllTextSafe(this.GetConfigFile(pluginName).FullName, SerializeConfig(config));
|
||||
Service<ReliableFileStorage>.Get()
|
||||
.WriteAllText(this.GetConfigFile(pluginName).FullName, SerializeConfig(config), workingPluginId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load plugin configuration.
|
||||
/// </summary>
|
||||
/// <param name="pluginName">Plugin name.</param>
|
||||
/// <param name="workingPluginId">WorkingPluginID of the plugin.</param>
|
||||
/// <returns>Plugin configuration.</returns>
|
||||
public IPluginConfiguration? Load(string pluginName)
|
||||
public IPluginConfiguration? Load(string pluginName, Guid workingPluginId)
|
||||
{
|
||||
var path = this.GetConfigFile(pluginName);
|
||||
|
||||
if (!path.Exists)
|
||||
return null;
|
||||
IPluginConfiguration? config = null;
|
||||
try
|
||||
{
|
||||
Service<ReliableFileStorage>.Get().ReadAllText(path.FullName, text =>
|
||||
{
|
||||
config = DeserializeConfig(text);
|
||||
if (config == null)
|
||||
throw new Exception("Read config was null.");
|
||||
}, workingPluginId);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
return DeserializeConfig(File.ReadAllText(path.FullName));
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
|
@ -7,12 +6,15 @@ using System.Runtime.InteropServices;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dalamud.Common;
|
||||
using Dalamud.Configuration.Internal;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.Gui.Internal;
|
||||
using Dalamud.Interface.Internal;
|
||||
using Dalamud.Plugin.Internal;
|
||||
using Dalamud.Storage;
|
||||
using Dalamud.Utility;
|
||||
using Dalamud.Utility.Timing;
|
||||
using PInvoke;
|
||||
using Serilog;
|
||||
|
||||
|
|
@ -28,6 +30,7 @@ namespace Dalamud;
|
|||
/// <summary>
|
||||
/// The main Dalamud class containing all subsystems.
|
||||
/// </summary>
|
||||
[ServiceManager.Service]
|
||||
internal sealed class Dalamud : IServiceType
|
||||
{
|
||||
#region Internals
|
||||
|
|
@ -40,26 +43,48 @@ internal sealed class Dalamud : IServiceType
|
|||
/// Initializes a new instance of the <see cref="Dalamud"/> class.
|
||||
/// </summary>
|
||||
/// <param name="info">DalamudStartInfo instance.</param>
|
||||
/// <param name="fs">ReliableFileStorage instance.</param>
|
||||
/// <param name="configuration">The Dalamud configuration.</param>
|
||||
/// <param name="mainThreadContinueEvent">Event used to signal the main thread to continue.</param>
|
||||
public Dalamud(DalamudStartInfo info, DalamudConfiguration configuration, IntPtr mainThreadContinueEvent)
|
||||
public Dalamud(DalamudStartInfo info, ReliableFileStorage fs, DalamudConfiguration configuration, IntPtr mainThreadContinueEvent)
|
||||
{
|
||||
this.StartInfo = info;
|
||||
|
||||
this.unloadSignal = new ManualResetEvent(false);
|
||||
this.unloadSignal.Reset();
|
||||
|
||||
// Directory resolved signatures(CS, our own) will be cached in
|
||||
var cacheDir = new DirectoryInfo(Path.Combine(this.StartInfo.WorkingDirectory!, "cachedSigs"));
|
||||
if (!cacheDir.Exists)
|
||||
cacheDir.Create();
|
||||
|
||||
// Set up the SigScanner for our target module
|
||||
TargetSigScanner scanner;
|
||||
using (Timings.Start("SigScanner Init"))
|
||||
{
|
||||
scanner = new TargetSigScanner(
|
||||
true, new FileInfo(Path.Combine(cacheDir.FullName, $"{this.StartInfo.GameVersion}.json")));
|
||||
}
|
||||
|
||||
ServiceManager.InitializeProvidedServicesAndClientStructs(this, info, configuration);
|
||||
ServiceManager.InitializeProvidedServices(this, fs, configuration, scanner);
|
||||
|
||||
// Set up FFXIVClientStructs
|
||||
this.SetupClientStructsResolver(cacheDir);
|
||||
|
||||
if (!configuration.IsResumeGameAfterPluginLoad)
|
||||
{
|
||||
NativeFunctions.SetEvent(mainThreadContinueEvent);
|
||||
try
|
||||
{
|
||||
_ = ServiceManager.InitializeEarlyLoadableServices();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "Service initialization failure");
|
||||
}
|
||||
ServiceManager.InitializeEarlyLoadableServices()
|
||||
.ContinueWith(t =>
|
||||
{
|
||||
if (t.IsCompletedSuccessfully)
|
||||
return;
|
||||
|
||||
Log.Error(t.Exception!, "Service initialization failure");
|
||||
Util.Fatal(
|
||||
"Dalamud failed to load all necessary services.\n\nThe game will continue, but you may not be able to use plugins.",
|
||||
"Dalamud", false);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -94,11 +119,16 @@ internal sealed class Dalamud : IServiceType
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the start information for this Dalamud instance.
|
||||
/// </summary>
|
||||
internal DalamudStartInfo StartInfo { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets location of stored assets.
|
||||
/// </summary>
|
||||
internal DirectoryInfo AssetDirectory => new(Service<DalamudStartInfo>.Get().AssetDirectory!);
|
||||
internal DirectoryInfo AssetDirectory => new(this.StartInfo.AssetDirectory!);
|
||||
|
||||
/// <summary>
|
||||
/// Signal to the crash handler process that we should restart the game.
|
||||
|
|
@ -167,10 +197,19 @@ internal sealed class Dalamud : IServiceType
|
|||
internal void ReplaceExceptionHandler()
|
||||
{
|
||||
var releaseSig = "40 55 53 56 48 8D AC 24 ?? ?? ?? ?? B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 85 ?? ?? ?? ?? 48 83 3D ?? ?? ?? ?? ??";
|
||||
var releaseFilter = Service<SigScanner>.Get().ScanText(releaseSig);
|
||||
var releaseFilter = Service<TargetSigScanner>.Get().ScanText(releaseSig);
|
||||
Log.Debug($"SE debug filter at {releaseFilter.ToInt64():X}");
|
||||
|
||||
var oldFilter = NativeFunctions.SetUnhandledExceptionFilter(releaseFilter);
|
||||
Log.Debug("Reset ExceptionFilter, old: {0}", oldFilter);
|
||||
}
|
||||
|
||||
private void SetupClientStructsResolver(DirectoryInfo cacheDir)
|
||||
{
|
||||
using (Timings.Start("CS Resolver Init"))
|
||||
{
|
||||
FFXIVClientStructs.Interop.Resolver.GetInstance.SetupSearchSpace(Service<TargetSigScanner>.Get().SearchBase, new FileInfo(Path.Combine(cacheDir.FullName, $"{this.StartInfo.GameVersion}_cs.json")));
|
||||
FFXIVClientStructs.Interop.Resolver.GetInstance.Resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Feature">
|
||||
<DalamudVersion>7.11.0.0</DalamudVersion>
|
||||
<DalamudVersion>9.0.0.0</DalamudVersion>
|
||||
<Description>XIV Launcher addon framework</Description>
|
||||
<AssemblyVersion>$(DalamudVersion)</AssemblyVersion>
|
||||
<Version>$(DalamudVersion)</Version>
|
||||
|
|
@ -68,7 +68,7 @@
|
|||
<PackageReference Include="goaaats.Reloaded.Hooks" Version="4.2.0-goat.4" />
|
||||
<PackageReference Include="goaaats.Reloaded.Assembler" Version="1.0.14-goat.2" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2021.2.0" />
|
||||
<PackageReference Include="Lumina" Version="3.10.2" />
|
||||
<PackageReference Include="Lumina" Version="3.11.0" />
|
||||
<PackageReference Include="Lumina.Excel" Version="6.4.0" />
|
||||
<PackageReference Include="MinSharp" Version="1.0.4" />
|
||||
<PackageReference Include="MonoModReorg.RuntimeDetour" Version="23.1.2-prerelease.1" />
|
||||
|
|
@ -77,6 +77,7 @@
|
|||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="sqlite-net-pcl" Version="1.8.116" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.333">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
|
@ -88,7 +89,7 @@
|
|||
<PackageReference Include="System.Resources.Extensions" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Dalamud.Interface\Dalamud.Interface.csproj" />
|
||||
<ProjectReference Include="..\Dalamud.Common\Dalamud.Common.csproj" />
|
||||
<ProjectReference Include="..\lib\FFXIVClientStructs\FFXIVClientStructs\FFXIVClientStructs.csproj" />
|
||||
<ProjectReference Include="..\lib\ImGuiScene\deps\ImGui.NET\src\ImGui.NET-472\ImGui.NET-472.csproj" />
|
||||
<ProjectReference Include="..\lib\ImGuiScene\deps\SDL2-CS\SDL2-CS.csproj" />
|
||||
|
|
@ -106,6 +107,10 @@
|
|||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Game\Addon\" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="AddRuntimeDependenciesToContent" BeforeTargets="GetCopyToOutputDirectoryItems" DependsOnTargets="GenerateBuildDependencyFile;GenerateBuildRuntimeConfigurationFiles">
|
||||
<ItemGroup>
|
||||
<ContentWithTargetPath Include="$(ProjectDepsFilePath)" CopyToOutputDirectory="PreserveNewest" TargetPath="$(ProjectDepsFileName)" />
|
||||
|
|
|
|||
|
|
@ -1,27 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
using Dalamud.Interface.Internal;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
using Dalamud.Utility.Timing;
|
||||
using ImGuiScene;
|
||||
using JetBrains.Annotations;
|
||||
using Lumina;
|
||||
using Lumina.Data;
|
||||
using Lumina.Data.Files;
|
||||
using Lumina.Data.Parsing.Tex.Buffers;
|
||||
using Lumina.Excel;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
using SharpDX.DXGI;
|
||||
|
||||
namespace Dalamud.Data;
|
||||
|
||||
|
|
@ -34,18 +27,15 @@ namespace Dalamud.Data;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IDataManager>]
|
||||
#pragma warning restore SA1015
|
||||
public sealed class DataManager : IDisposable, IServiceType, IDataManager
|
||||
internal sealed class DataManager : IDisposable, IServiceType, IDataManager
|
||||
{
|
||||
private const string IconFileFormat = "ui/icon/{0:D3}000/{1}{2:D6}.tex";
|
||||
private const string HighResolutionIconFileFormat = "ui/icon/{0:D3}000/{1}{2:D6}_hr1.tex";
|
||||
|
||||
private readonly Thread luminaResourceThread;
|
||||
private readonly CancellationTokenSource luminaCancellationTokenSource;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private DataManager(DalamudStartInfo dalamudStartInfo, Dalamud dalamud)
|
||||
private DataManager(Dalamud dalamud)
|
||||
{
|
||||
this.Language = dalamudStartInfo.Language;
|
||||
this.Language = (ClientLanguage)dalamud.StartInfo.Language;
|
||||
|
||||
// Set up default values so plugins do not null-reference when data is being loaded.
|
||||
this.ClientOpCodes = this.ServerOpCodes = new ReadOnlyDictionary<string, ushort>(new Dictionary<string, ushort>());
|
||||
|
|
@ -93,17 +83,20 @@ public sealed class DataManager : IDisposable, IServiceType, IDataManager
|
|||
|
||||
Log.Information("Lumina is ready: {0}", this.GameData.DataPath);
|
||||
|
||||
try
|
||||
if (!dalamud.StartInfo.TroubleshootingPackData.IsNullOrEmpty())
|
||||
{
|
||||
var tsInfo =
|
||||
JsonConvert.DeserializeObject<LauncherTroubleshootingInfo>(
|
||||
dalamudStartInfo.TroubleshootingPackData);
|
||||
this.HasModifiedGameDataFiles =
|
||||
tsInfo?.IndexIntegrity is LauncherTroubleshootingInfo.IndexIntegrityResult.Failed or LauncherTroubleshootingInfo.IndexIntegrityResult.Exception;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
try
|
||||
{
|
||||
var tsInfo =
|
||||
JsonConvert.DeserializeObject<LauncherTroubleshootingInfo>(
|
||||
dalamud.StartInfo.TroubleshootingPackData);
|
||||
this.HasModifiedGameDataFiles =
|
||||
tsInfo?.IndexIntegrity is LauncherTroubleshootingInfo.IndexIntegrityResult.Failed or LauncherTroubleshootingInfo.IndexIntegrityResult.Exception;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -137,10 +130,14 @@ public sealed class DataManager : IDisposable, IServiceType, IDataManager
|
|||
/// <inheritdoc/>
|
||||
public ClientLanguage Language { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <summary>
|
||||
/// Gets a list of server opcodes.
|
||||
/// </summary>
|
||||
public ReadOnlyDictionary<string, ushort> ServerOpCodes { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of client opcodes.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public ReadOnlyDictionary<string, ushort> ClientOpCodes { get; private set; }
|
||||
|
||||
|
|
@ -150,12 +147,14 @@ public sealed class DataManager : IDisposable, IServiceType, IDataManager
|
|||
/// <inheritdoc/>
|
||||
public ExcelModule Excel => this.GameData.Excel;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsDataReady { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool HasModifiedGameDataFiles { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether Game Data is ready to be read.
|
||||
/// </summary>
|
||||
internal bool IsDataReady { get; private set; }
|
||||
|
||||
#region Lumina Wrappers
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
@ -183,158 +182,6 @@ public sealed class DataManager : IDisposable, IServiceType, IDataManager
|
|||
public bool FileExists(string path)
|
||||
=> this.GameData.FileExists(path);
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="TexFile"/> containing the icon with the given ID.
|
||||
/// </summary>
|
||||
/// <param name="iconId">The icon ID.</param>
|
||||
/// <returns>The <see cref="TexFile"/> containing the icon.</returns>
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
public TexFile? GetIcon(uint iconId)
|
||||
=> this.GetIcon(this.Language, iconId, false);
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
public TexFile? GetIcon(uint iconId, bool highResolution)
|
||||
=> this.GetIcon(this.Language, iconId, highResolution);
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
public TexFile? GetIcon(bool isHq, uint iconId)
|
||||
{
|
||||
var type = isHq ? "hq/" : string.Empty;
|
||||
return this.GetIcon(type, iconId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="TexFile"/> containing the icon with the given ID, of the given language.
|
||||
/// </summary>
|
||||
/// <param name="iconLanguage">The requested language.</param>
|
||||
/// <param name="iconId">The icon ID.</param>
|
||||
/// <returns>The <see cref="TexFile"/> containing the icon.</returns>
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
public TexFile? GetIcon(ClientLanguage iconLanguage, uint iconId)
|
||||
=> this.GetIcon(iconLanguage, iconId, false);
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
public TexFile? GetIcon(ClientLanguage iconLanguage, uint iconId, bool highResolution)
|
||||
{
|
||||
var type = iconLanguage switch
|
||||
{
|
||||
ClientLanguage.Japanese => "ja/",
|
||||
ClientLanguage.English => "en/",
|
||||
ClientLanguage.German => "de/",
|
||||
ClientLanguage.French => "fr/",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(iconLanguage), $"Unknown Language: {iconLanguage}"),
|
||||
};
|
||||
|
||||
return this.GetIcon(type, iconId, highResolution);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="TexFile"/> containing the icon with the given ID, of the given type.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of the icon (e.g. 'hq' to get the HQ variant of an item icon).</param>
|
||||
/// <param name="iconId">The icon ID.</param>
|
||||
/// <returns>The <see cref="TexFile"/> containing the icon.</returns>
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
public TexFile? GetIcon(string? type, uint iconId)
|
||||
=> this.GetIcon(type, iconId, false);
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
public TexFile? GetIcon(string? type, uint iconId, bool highResolution)
|
||||
{
|
||||
var format = highResolution ? HighResolutionIconFileFormat : IconFileFormat;
|
||||
|
||||
type ??= string.Empty;
|
||||
if (type.Length > 0 && !type.EndsWith("/"))
|
||||
type += "/";
|
||||
|
||||
var filePath = string.Format(format, iconId / 1000, type, iconId);
|
||||
var file = this.GetFile<TexFile>(filePath);
|
||||
|
||||
if (type == string.Empty || file != default)
|
||||
return file;
|
||||
|
||||
// Couldn't get specific type, try for generic version.
|
||||
filePath = string.Format(format, iconId / 1000, string.Empty, iconId);
|
||||
file = this.GetFile<TexFile>(filePath);
|
||||
return file;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
public TexFile? GetHqIcon(uint iconId)
|
||||
=> this.GetIcon(true, iconId);
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
[return: NotNullIfNotNull(nameof(tex))]
|
||||
public TextureWrap? GetImGuiTexture(TexFile? tex)
|
||||
{
|
||||
if (tex is null)
|
||||
return null;
|
||||
|
||||
var im = Service<InterfaceManager>.Get();
|
||||
var buffer = tex.TextureBuffer;
|
||||
var bpp = 1 << (((int)tex.Header.Format & (int)TexFile.TextureFormat.BppMask) >>
|
||||
(int)TexFile.TextureFormat.BppShift);
|
||||
|
||||
var (dxgiFormat, conversion) = TexFile.GetDxgiFormatFromTextureFormat(tex.Header.Format, false);
|
||||
if (conversion != TexFile.DxgiFormatConversion.NoConversion || !im.SupportsDxgiFormat((Format)dxgiFormat))
|
||||
{
|
||||
dxgiFormat = (int)Format.B8G8R8A8_UNorm;
|
||||
buffer = buffer.Filter(0, 0, TexFile.TextureFormat.B8G8R8A8);
|
||||
bpp = 32;
|
||||
}
|
||||
|
||||
var pitch = buffer is BlockCompressionTextureBuffer
|
||||
? Math.Max(1, (buffer.Width + 3) / 4) * 2 * bpp
|
||||
: ((buffer.Width * bpp) + 7) / 8;
|
||||
return im.LoadImageFromDxgiFormat(buffer.RawData, pitch, buffer.Width, buffer.Height, (Format)dxgiFormat);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
public TextureWrap? GetImGuiTexture(string path)
|
||||
=> this.GetImGuiTexture(this.GetFile<TexFile>(path));
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="TextureWrap"/> containing the icon with the given ID.
|
||||
/// </summary>
|
||||
/// <param name="iconId">The icon ID.</param>
|
||||
/// <returns>The <see cref="TextureWrap"/> containing the icon.</returns>
|
||||
/// TODO(v9): remove in api9 in favor of GetImGuiTextureIcon(uint iconId, bool highResolution)
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
public TextureWrap? GetImGuiTextureIcon(uint iconId)
|
||||
=> this.GetImGuiTexture(this.GetIcon(iconId, false));
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
public TextureWrap? GetImGuiTextureIcon(uint iconId, bool highResolution)
|
||||
=> this.GetImGuiTexture(this.GetIcon(iconId, highResolution));
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
public TextureWrap? GetImGuiTextureIcon(bool isHq, uint iconId)
|
||||
=> this.GetImGuiTexture(this.GetIcon(isHq, iconId));
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
public TextureWrap? GetImGuiTextureIcon(ClientLanguage iconLanguage, uint iconId)
|
||||
=> this.GetImGuiTexture(this.GetIcon(iconLanguage, iconId));
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
public TextureWrap? GetImGuiTextureIcon(string type, uint iconId)
|
||||
=> this.GetImGuiTexture(this.GetIcon(type, iconId));
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Obsolete("Use ITextureProvider instead")]
|
||||
public TextureWrap? GetImGuiTextureHqIcon(uint iconId)
|
||||
=> this.GetImGuiTexture(this.GetHqIcon(iconId));
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
|
@ -6,10 +5,12 @@ using System.Runtime.InteropServices;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dalamud.Common;
|
||||
using Dalamud.Configuration.Internal;
|
||||
using Dalamud.Logging.Internal;
|
||||
using Dalamud.Logging.Retention;
|
||||
using Dalamud.Plugin.Internal;
|
||||
using Dalamud.Storage;
|
||||
using Dalamud.Support;
|
||||
using Dalamud.Utility;
|
||||
using Newtonsoft.Json;
|
||||
|
|
@ -137,7 +138,8 @@ public sealed class EntryPoint
|
|||
SerilogEventSink.Instance.LogLine += SerilogOnLogLine;
|
||||
|
||||
// Load configuration first to get some early persistent state, like log level
|
||||
var configuration = DalamudConfiguration.Load(info.ConfigurationPath!);
|
||||
var fs = new ReliableFileStorage(Path.GetDirectoryName(info.ConfigurationPath)!);
|
||||
var configuration = DalamudConfiguration.Load(info.ConfigurationPath!, fs);
|
||||
|
||||
// Set the appropriate logging level from the configuration
|
||||
if (!configuration.LogSynchronously)
|
||||
|
|
@ -161,15 +163,18 @@ public sealed class EntryPoint
|
|||
Log.Information(new string('-', 80));
|
||||
Log.Information("Initializing a session..");
|
||||
|
||||
if (string.IsNullOrEmpty(info.WorkingDirectory))
|
||||
throw new Exception("Working directory was invalid");
|
||||
|
||||
Reloaded.Hooks.Tools.Utilities.FasmBasePath = new DirectoryInfo(info.WorkingDirectory);
|
||||
|
||||
// This is due to GitHub not supporting TLS 1.0, so we enable all TLS versions globally
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls;
|
||||
|
||||
if (!Util.IsLinux())
|
||||
if (!Util.IsWine())
|
||||
InitSymbolHandler(info);
|
||||
|
||||
var dalamud = new Dalamud(info, configuration, mainThreadContinueEvent);
|
||||
var dalamud = new Dalamud(info, fs, configuration, mainThreadContinueEvent);
|
||||
Log.Information("This is Dalamud - Core: {GitHash}, CS: {CsGitHash} [{CsVersion}]", Util.GetGitHash(), Util.GetGitHashClientStructs(), FFXIVClientStructs.Interop.Resolver.Version);
|
||||
|
||||
dalamud.WaitForUnload();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Reimplementation of CursorType.
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
using System;
|
||||
|
||||
using Dalamud.Memory;
|
||||
using Dalamud.Memory;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Events;
|
||||
|
||||
/// <summary>
|
||||
/// This class represents a registered event that a plugin registers with a native ui node.
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Class that represents a addon event handle.
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Event listener class for managing custom events.
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Dalamud.Game.Addon.Lifecycle;
|
||||
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
|
|
@ -11,7 +12,7 @@ using Dalamud.Plugin.Services;
|
|||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Service provider for addon event management.
|
||||
|
|
@ -40,7 +41,7 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType
|
|||
private AddonCursorType? cursorOverride;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private AddonEventManager(SigScanner sigScanner)
|
||||
private AddonEventManager(TargetSigScanner sigScanner)
|
||||
{
|
||||
this.address = new AddonEventManagerAddressResolver();
|
||||
this.address.Setup(sigScanner);
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Events;
|
||||
|
||||
/// <summary>
|
||||
/// AddonEventManager memory address resolver.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Reimplementation of AtkEventType.
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Interface representing the data used for managing AddonEvents.
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Dalamud.Game.Gui;
|
||||
|
|
@ -8,7 +7,7 @@ using Dalamud.Memory;
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Class to manage creating and cleaning up events per-plugin.
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using Dalamud.Memory;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for AddonLifecycle AddonArgTypes.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Addon argument data for Finalize events.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Addon argument data for Finalize events.
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Addon argument data for Finalize events.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Addon argument data for Finalize events.
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
using System;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Addon argument data for Setup events.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Addon argument data for Finalize events.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Lifecycle;
|
||||
|
||||
/// <summary>
|
||||
/// Enumeration for available AddonLifecycle arg data.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Lifecycle;
|
||||
|
||||
/// <summary>
|
||||
/// Enumeration for available AddonLifecycle events.
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Hooking.Internal;
|
||||
using Dalamud.IoC;
|
||||
|
|
@ -11,7 +11,7 @@ using Dalamud.Logging.Internal;
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Lifecycle;
|
||||
|
||||
/// <summary>
|
||||
/// This class provides events for in-game addon lifecycles.
|
||||
|
|
@ -38,7 +38,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
|||
private readonly List<AddonLifecycleEventListener> eventListeners = new();
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private AddonLifecycle(SigScanner sigScanner)
|
||||
private AddonLifecycle(TargetSigScanner sigScanner)
|
||||
{
|
||||
this.address = new AddonLifecycleAddressResolver();
|
||||
this.address.Setup(sigScanner);
|
||||
|
|
@ -97,7 +97,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
|||
}
|
||||
|
||||
// Used to prevent concurrency issues if plugins try to register during iteration of listeners.
|
||||
private void OnFrameworkUpdate(Framework unused)
|
||||
private void OnFrameworkUpdate(IFramework unused)
|
||||
{
|
||||
if (this.newEventListeners.Any())
|
||||
{
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Lifecycle;
|
||||
|
||||
/// <summary>
|
||||
/// AddonLifecycleService memory address resolver.
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
|
||||
namespace Dalamud.Game.Addon;
|
||||
namespace Dalamud.Game.Addon.Lifecycle;
|
||||
|
||||
/// <summary>
|
||||
/// This class is a helper for tracking and invoking listener delegates.
|
||||
|
|
@ -10,7 +10,7 @@ namespace Dalamud.Game;
|
|||
/// <summary>
|
||||
/// Base memory address resolver.
|
||||
/// </summary>
|
||||
public abstract class BaseAddressResolver
|
||||
internal abstract class BaseAddressResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a list of memory addresses that were found, to list in /xldata.
|
||||
|
|
@ -22,15 +22,6 @@ public abstract class BaseAddressResolver
|
|||
/// </summary>
|
||||
protected bool IsResolved { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Setup the resolver, calling the appropriate method based on the process architecture,
|
||||
/// using the default SigScanner.
|
||||
///
|
||||
/// For plugins. Not intended to be called from Dalamud Service{T} constructors.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public void Setup() => this.Setup(Service<SigScanner>.Get());
|
||||
|
||||
/// <summary>
|
||||
/// Setup the resolver, calling the appropriate method based on the process architecture.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
|
@ -14,8 +13,6 @@ using Dalamud.Game.Text.SeStringHandling.Payloads;
|
|||
using Dalamud.Interface.Internal;
|
||||
using Dalamud.Interface.Internal.Notifications;
|
||||
using Dalamud.Interface.Internal.Windows;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Internal;
|
||||
using Dalamud.Utility;
|
||||
using Serilog;
|
||||
|
|
@ -25,10 +22,8 @@ namespace Dalamud.Game;
|
|||
/// <summary>
|
||||
/// Chat events and public helper functions.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
public class ChatHandlers : IServiceType
|
||||
internal class ChatHandlers : IServiceType
|
||||
{
|
||||
// private static readonly Dictionary<string, string> UnicodeToDiscordEmojiDict = new()
|
||||
// {
|
||||
|
|
@ -106,6 +101,9 @@ public class ChatHandlers : IServiceType
|
|||
|
||||
private readonly DalamudLinkPayload openInstallerWindowLink;
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly Dalamud dalamud = Service<Dalamud>.Get();
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly DalamudConfiguration configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
|
|
@ -134,22 +132,6 @@ public class ChatHandlers : IServiceType
|
|||
/// </summary>
|
||||
public bool IsAutoUpdateComplete { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Convert a TextPayload to SeString and wrap in italics payloads.
|
||||
/// </summary>
|
||||
/// <param name="text">Text to convert.</param>
|
||||
/// <returns>SeString payload of italicized text.</returns>
|
||||
public static SeString MakeItalics(string text)
|
||||
=> MakeItalics(new TextPayload(text));
|
||||
|
||||
/// <summary>
|
||||
/// Convert a TextPayload to SeString and wrap in italics payloads.
|
||||
/// </summary>
|
||||
/// <param name="text">Text to convert.</param>
|
||||
/// <returns>SeString payload of italicized text.</returns>
|
||||
public static SeString MakeItalics(TextPayload text)
|
||||
=> new(EmphasisItalicPayload.ItalicsOn, text, EmphasisItalicPayload.ItalicsOff);
|
||||
|
||||
private void OnCheckMessageHandled(XivChatType type, uint senderid, ref SeString sender, ref SeString message, ref bool isHandled)
|
||||
{
|
||||
var textVal = message.TextValue;
|
||||
|
|
@ -178,7 +160,6 @@ public class ChatHandlers : IServiceType
|
|||
|
||||
private void OnChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled)
|
||||
{
|
||||
var startInfo = Service<DalamudStartInfo>.Get();
|
||||
var clientState = Service<ClientState.ClientState>.GetNullable();
|
||||
if (clientState == null)
|
||||
return;
|
||||
|
|
@ -200,7 +181,7 @@ public class ChatHandlers : IServiceType
|
|||
|
||||
if (type == XivChatType.RetainerSale)
|
||||
{
|
||||
foreach (var regex in this.retainerSaleRegexes[startInfo.Language])
|
||||
foreach (var regex in this.retainerSaleRegexes[(ClientLanguage)this.dalamud.StartInfo.Language])
|
||||
{
|
||||
var matchInfo = regex.Match(message.TextValue);
|
||||
|
||||
|
|
@ -264,7 +245,7 @@ public class ChatHandlers : IServiceType
|
|||
|
||||
if (string.IsNullOrEmpty(this.configuration.LastVersion) || !assemblyVersion.StartsWith(this.configuration.LastVersion))
|
||||
{
|
||||
chatGui.PrintChat(new XivChatEntry
|
||||
chatGui.Print(new XivChatEntry
|
||||
{
|
||||
Message = Loc.Localize("DalamudUpdated", "Dalamud has been updated successfully! Please check the discord for a full changelog."),
|
||||
Type = XivChatType.Notice,
|
||||
|
|
@ -321,7 +302,7 @@ public class ChatHandlers : IServiceType
|
|||
}
|
||||
else
|
||||
{
|
||||
chatGui.PrintChat(new XivChatEntry
|
||||
chatGui.Print(new XivChatEntry
|
||||
{
|
||||
Message = new SeString(new List<Payload>()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Dalamud.Game.ClientState.Aetherytes;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IAetheryteList>]
|
||||
#pragma warning restore SA1015
|
||||
public sealed unsafe partial class AetheryteList : IServiceType, IAetheryteList
|
||||
internal sealed unsafe partial class AetheryteList : IServiceType, IAetheryteList
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly ClientState clientState = Service<ClientState>.Get();
|
||||
|
|
@ -78,7 +78,7 @@ public sealed unsafe partial class AetheryteList : IServiceType, IAetheryteList
|
|||
/// <summary>
|
||||
/// This collection represents the list of available Aetherytes in the Teleport window.
|
||||
/// </summary>
|
||||
public sealed partial class AetheryteList
|
||||
internal sealed partial class AetheryteList
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public int Count => this.Length;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ namespace Dalamud.Game.ClientState.Buddy;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IBuddyList>]
|
||||
#pragma warning restore SA1015
|
||||
public sealed partial class BuddyList : IServiceType, IBuddyList
|
||||
internal sealed partial class BuddyList : IServiceType, IBuddyList
|
||||
{
|
||||
private const uint InvalidObjectID = 0xE0000000;
|
||||
|
||||
|
|
@ -55,18 +55,6 @@ public sealed partial class BuddyList : IServiceType, IBuddyList
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the local player's companion is present.
|
||||
/// </summary>
|
||||
[Obsolete("Use CompanionBuddy != null", false)]
|
||||
public bool CompanionBuddyPresent => this.CompanionBuddy != null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the local player's pet is present.
|
||||
/// </summary>
|
||||
[Obsolete("Use PetBuddy != null", false)]
|
||||
public bool PetBuddyPresent => this.PetBuddy != null;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public BuddyMember? CompanionBuddy
|
||||
{
|
||||
|
|
@ -147,7 +135,7 @@ public sealed partial class BuddyList : IServiceType, IBuddyList
|
|||
/// <summary>
|
||||
/// This collection represents the buddies present in your squadron or trust party.
|
||||
/// </summary>
|
||||
public sealed partial class BuddyList
|
||||
internal sealed partial class BuddyList
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
int IReadOnlyCollection<BuddyMember>.Count => this.Length;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Dalamud.Data;
|
||||
|
|
@ -9,24 +8,25 @@ using Dalamud.Game.Network.Internal;
|
|||
using Dalamud.Hooking;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Logging.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using Serilog;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
|
||||
using Action = System.Action;
|
||||
|
||||
namespace Dalamud.Game.ClientState;
|
||||
|
||||
/// <summary>
|
||||
/// This class represents the state of the game client at the time of access.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IClientState>]
|
||||
#pragma warning restore SA1015
|
||||
public sealed class ClientState : IDisposable, IServiceType, IClientState
|
||||
internal sealed class ClientState : IDisposable, IServiceType, IClientState
|
||||
{
|
||||
private static readonly ModuleLog Log = new("ClientState");
|
||||
|
||||
private readonly GameLifecycle lifecycle;
|
||||
private readonly ClientStateAddressResolver address;
|
||||
private readonly Hook<SetupTerritoryTypeDelegate> setupTerritoryTypeHook;
|
||||
|
|
@ -38,10 +38,10 @@ public sealed class ClientState : IDisposable, IServiceType, IClientState
|
|||
private readonly NetworkHandlers networkHandlers = Service<NetworkHandlers>.Get();
|
||||
|
||||
private bool lastConditionNone = true;
|
||||
private bool lastFramePvP = false;
|
||||
private bool lastFramePvP;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private ClientState(SigScanner sigScanner, DalamudStartInfo startInfo, GameLifecycle lifecycle)
|
||||
private ClientState(TargetSigScanner sigScanner, Dalamud dalamud, GameLifecycle lifecycle)
|
||||
{
|
||||
this.lifecycle = lifecycle;
|
||||
this.address = new ClientStateAddressResolver();
|
||||
|
|
@ -49,7 +49,7 @@ public sealed class ClientState : IDisposable, IServiceType, IClientState
|
|||
|
||||
Log.Verbose("===== C L I E N T S T A T E =====");
|
||||
|
||||
this.ClientLanguage = startInfo.Language;
|
||||
this.ClientLanguage = (ClientLanguage)dalamud.StartInfo.Language;
|
||||
|
||||
Log.Verbose($"SetupTerritoryType address 0x{this.address.SetupTerritoryType.ToInt64():X}");
|
||||
|
||||
|
|
@ -64,22 +64,22 @@ public sealed class ClientState : IDisposable, IServiceType, IClientState
|
|||
private delegate IntPtr SetupTerritoryTypeDelegate(IntPtr manager, ushort terriType);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ushort> TerritoryChanged;
|
||||
public event Action<ushort>? TerritoryChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler Login;
|
||||
public event Action? Login;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler Logout;
|
||||
public event Action? Logout;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event Action EnterPvP;
|
||||
public event Action? EnterPvP;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event Action LeavePvP;
|
||||
public event Action? LeavePvP;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<Lumina.Excel.GeneratedSheets.ContentFinderCondition> CfPop;
|
||||
public event Action<ContentFinderCondition>? CfPop;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ClientLanguage ClientLanguage { get; }
|
||||
|
|
@ -102,6 +102,9 @@ public sealed class ClientState : IDisposable, IServiceType, IClientState
|
|||
/// <inheritdoc/>
|
||||
public bool IsPvPExcludingDen { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsGPosing => GameMain.IsInGPose();
|
||||
|
||||
/// <summary>
|
||||
/// Gets client state address resolver.
|
||||
/// </summary>
|
||||
|
|
@ -126,19 +129,19 @@ public sealed class ClientState : IDisposable, IServiceType, IClientState
|
|||
private IntPtr SetupTerritoryTypeDetour(IntPtr manager, ushort terriType)
|
||||
{
|
||||
this.TerritoryType = terriType;
|
||||
this.TerritoryChanged?.InvokeSafely(this, terriType);
|
||||
this.TerritoryChanged?.InvokeSafely(terriType);
|
||||
|
||||
Log.Debug("TerritoryType changed: {0}", terriType);
|
||||
|
||||
return this.setupTerritoryTypeHook.Original(manager, terriType);
|
||||
}
|
||||
|
||||
private void NetworkHandlersOnCfPop(object sender, Lumina.Excel.GeneratedSheets.ContentFinderCondition e)
|
||||
private void NetworkHandlersOnCfPop(ContentFinderCondition e)
|
||||
{
|
||||
this.CfPop?.InvokeSafely(this, e);
|
||||
this.CfPop?.InvokeSafely(e);
|
||||
}
|
||||
|
||||
private void FrameworkOnOnUpdateEvent(Framework framework1)
|
||||
private void FrameworkOnOnUpdateEvent(IFramework framework1)
|
||||
{
|
||||
var condition = Service<Conditions.Condition>.GetNullable();
|
||||
var gameGui = Service<GameGui>.GetNullable();
|
||||
|
|
@ -147,12 +150,12 @@ public sealed class ClientState : IDisposable, IServiceType, IClientState
|
|||
if (condition == null || gameGui == null || data == null)
|
||||
return;
|
||||
|
||||
if (condition.Any() && this.lastConditionNone == true && this.LocalPlayer != null)
|
||||
if (condition.Any() && this.lastConditionNone && this.LocalPlayer != null)
|
||||
{
|
||||
Log.Debug("Is login");
|
||||
this.lastConditionNone = false;
|
||||
this.IsLoggedIn = true;
|
||||
this.Login?.InvokeSafely(this, null);
|
||||
this.Login?.InvokeSafely();
|
||||
gameGui.ResetUiHideState();
|
||||
|
||||
this.lifecycle.ResetLogout();
|
||||
|
|
@ -163,7 +166,7 @@ public sealed class ClientState : IDisposable, IServiceType, IClientState
|
|||
Log.Debug("Is logout");
|
||||
this.lastConditionNone = true;
|
||||
this.IsLoggedIn = false;
|
||||
this.Logout?.InvokeSafely(this, null);
|
||||
this.Logout?.InvokeSafely();
|
||||
gameGui.ResetUiHideState();
|
||||
|
||||
this.lifecycle.SetLogout();
|
||||
|
|
@ -187,3 +190,103 @@ public sealed class ClientState : IDisposable, IServiceType, IClientState
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plugin-scoped version of a GameConfig service.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.ScopedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IClientState>]
|
||||
#pragma warning restore SA1015
|
||||
internal class ClientStatePluginScoped : IDisposable, IServiceType, IClientState
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly ClientState clientStateService = Service<ClientState>.Get();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ClientStatePluginScoped"/> class.
|
||||
/// </summary>
|
||||
internal ClientStatePluginScoped()
|
||||
{
|
||||
this.clientStateService.TerritoryChanged += this.TerritoryChangedForward;
|
||||
this.clientStateService.Login += this.LoginForward;
|
||||
this.clientStateService.Logout += this.LogoutForward;
|
||||
this.clientStateService.EnterPvP += this.EnterPvPForward;
|
||||
this.clientStateService.LeavePvP += this.ExitPvPForward;
|
||||
this.clientStateService.CfPop += this.ContentFinderPopForward;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event Action<ushort>? TerritoryChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event Action? Login;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event Action? Logout;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event Action? EnterPvP;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event Action? LeavePvP;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event Action<ContentFinderCondition>? CfPop;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ClientLanguage ClientLanguage => this.clientStateService.ClientLanguage;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ushort TerritoryType => this.clientStateService.TerritoryType;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public PlayerCharacter? LocalPlayer => this.clientStateService.LocalPlayer;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ulong LocalContentId => this.clientStateService.LocalContentId;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsLoggedIn => this.clientStateService.IsLoggedIn;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsPvP => this.clientStateService.IsPvP;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsPvPExcludingDen => this.clientStateService.IsPvPExcludingDen;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsGPosing => this.clientStateService.IsGPosing;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.clientStateService.TerritoryChanged -= this.TerritoryChangedForward;
|
||||
this.clientStateService.Login -= this.LoginForward;
|
||||
this.clientStateService.Logout -= this.LogoutForward;
|
||||
this.clientStateService.EnterPvP -= this.EnterPvPForward;
|
||||
this.clientStateService.LeavePvP -= this.ExitPvPForward;
|
||||
this.clientStateService.CfPop -= this.ContentFinderPopForward;
|
||||
|
||||
this.TerritoryChanged = null;
|
||||
this.Login = null;
|
||||
this.Logout = null;
|
||||
this.EnterPvP = null;
|
||||
this.LeavePvP = null;
|
||||
this.CfPop = null;
|
||||
}
|
||||
|
||||
private void TerritoryChangedForward(ushort territoryId) => this.TerritoryChanged?.Invoke(territoryId);
|
||||
|
||||
private void LoginForward() => this.Login?.Invoke();
|
||||
|
||||
private void LogoutForward() => this.Logout?.Invoke();
|
||||
|
||||
private void EnterPvPForward() => this.EnterPvP?.Invoke();
|
||||
|
||||
private void ExitPvPForward() => this.LeavePvP?.Invoke();
|
||||
|
||||
private void ContentFinderPopForward(ContentFinderCondition cfc) => this.CfPop?.Invoke(cfc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Dalamud.Game.ClientState;
|
|||
/// <summary>
|
||||
/// Client state memory address resolver.
|
||||
/// </summary>
|
||||
public sealed class ClientStateAddressResolver : BaseAddressResolver
|
||||
internal sealed class ClientStateAddressResolver : BaseAddressResolver
|
||||
{
|
||||
// Static offsets
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Conditions;
|
||||
|
|
@ -9,16 +8,15 @@ namespace Dalamud.Game.ClientState.Conditions;
|
|||
/// <summary>
|
||||
/// Provides access to conditions (generally player state). You can check whether a player is in combat, mounted, etc.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
public sealed partial class Condition : IServiceType
|
||||
internal sealed partial class Condition : IServiceType, ICondition
|
||||
{
|
||||
/// <summary>
|
||||
/// The current max number of conditions. You can get this just by looking at the condition sheet and how many rows it has.
|
||||
/// Gets the current max number of conditions. You can get this just by looking at the condition sheet and how many rows it has.
|
||||
/// </summary>
|
||||
public const int MaxConditionEntries = 104;
|
||||
|
||||
internal const int MaxConditionEntries = 104;
|
||||
|
||||
private readonly bool[] cache = new bool[MaxConditionEntries];
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
|
|
@ -27,29 +25,17 @@ public sealed partial class Condition : IServiceType
|
|||
var resolver = clientState.AddressResolver;
|
||||
this.Address = resolver.ConditionFlags;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event ICondition.ConditionChangeDelegate? ConditionChange;
|
||||
|
||||
/// <summary>
|
||||
/// A delegate type used with the <see cref="ConditionChange"/> event.
|
||||
/// </summary>
|
||||
/// <param name="flag">The changed condition.</param>
|
||||
/// <param name="value">The value the condition is set to.</param>
|
||||
public delegate void ConditionChangeDelegate(ConditionFlag flag, bool value);
|
||||
/// <inheritdoc/>
|
||||
public int MaxEntries => MaxConditionEntries;
|
||||
|
||||
/// <summary>
|
||||
/// Event that gets fired when a condition is set.
|
||||
/// Should only get fired for actual changes, so the previous value will always be !value.
|
||||
/// </summary>
|
||||
public event ConditionChangeDelegate? ConditionChange;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the condition array base pointer.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public IntPtr Address { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Check the value of a specific condition/state flag.
|
||||
/// </summary>
|
||||
/// <param name="flag">The condition flag to check.</param>
|
||||
/// <inheritdoc/>
|
||||
public unsafe bool this[int flag]
|
||||
{
|
||||
get
|
||||
|
|
@ -61,14 +47,11 @@ public sealed partial class Condition : IServiceType
|
|||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="this[int]"/>
|
||||
public unsafe bool this[ConditionFlag flag]
|
||||
/// <inheritdoc/>
|
||||
public bool this[ConditionFlag flag]
|
||||
=> this[(int)flag];
|
||||
|
||||
/// <summary>
|
||||
/// Check if any condition flags are set.
|
||||
/// </summary>
|
||||
/// <returns>Whether any single flag is set.</returns>
|
||||
/// <inheritdoc/>
|
||||
public bool Any()
|
||||
{
|
||||
for (var i = 0; i < MaxConditionEntries; i++)
|
||||
|
|
@ -81,6 +64,21 @@ public sealed partial class Condition : IServiceType
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Any(params ConditionFlag[] flags)
|
||||
{
|
||||
foreach (var flag in flags)
|
||||
{
|
||||
// this[i] performs range checking, so no need to check here
|
||||
if (this[flag])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[ServiceManager.CallWhenServicesReady]
|
||||
private void ContinueConstruction(Framework framework)
|
||||
|
|
@ -92,7 +90,7 @@ public sealed partial class Condition : IServiceType
|
|||
framework.Update += this.FrameworkUpdate;
|
||||
}
|
||||
|
||||
private void FrameworkUpdate(Framework framework)
|
||||
private void FrameworkUpdate(IFramework framework)
|
||||
{
|
||||
for (var i = 0; i < MaxConditionEntries; i++)
|
||||
{
|
||||
|
|
@ -118,7 +116,7 @@ public sealed partial class Condition : IServiceType
|
|||
/// <summary>
|
||||
/// Provides access to conditions (generally player state). You can check whether a player is in combat, mounted, etc.
|
||||
/// </summary>
|
||||
public sealed partial class Condition : IDisposable
|
||||
internal sealed partial class Condition : IDisposable
|
||||
{
|
||||
private bool isDisposed;
|
||||
|
||||
|
|
@ -152,3 +150,54 @@ public sealed partial class Condition : IDisposable
|
|||
this.isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plugin-scoped version of a Condition service.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.ScopedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<ICondition>]
|
||||
#pragma warning restore SA1015
|
||||
internal class ConditionPluginScoped : IDisposable, IServiceType, ICondition
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly Condition conditionService = Service<Condition>.Get();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConditionPluginScoped"/> class.
|
||||
/// </summary>
|
||||
internal ConditionPluginScoped()
|
||||
{
|
||||
this.conditionService.ConditionChange += this.ConditionChangedForward;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event ICondition.ConditionChangeDelegate? ConditionChange;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int MaxEntries => this.conditionService.MaxEntries;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IntPtr Address => this.conditionService.Address;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool this[int flag] => this.conditionService[flag];
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.conditionService.ConditionChange -= this.ConditionChangedForward;
|
||||
|
||||
this.ConditionChange = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Any() => this.conditionService.Any();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Any(params ConditionFlag[] flags) => this.conditionService.Any(flags);
|
||||
|
||||
private void ConditionChangedForward(ConditionFlag flag, bool value) => this.ConditionChange?.Invoke(flag, value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Dalamud.Game.ClientState.Fates;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IFateTable>]
|
||||
#pragma warning restore SA1015
|
||||
public sealed partial class FateTable : IServiceType, IFateTable
|
||||
internal sealed partial class FateTable : IServiceType, IFateTable
|
||||
{
|
||||
private readonly ClientStateAddressResolver address;
|
||||
|
||||
|
|
@ -110,7 +110,7 @@ public sealed partial class FateTable : IServiceType, IFateTable
|
|||
/// <summary>
|
||||
/// This collection represents the currently available Fate events.
|
||||
/// </summary>
|
||||
public sealed partial class FateTable
|
||||
internal sealed partial class FateTable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
int IReadOnlyCollection<Fate>.Count => this.Length;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Dalamud.Game.ClientState.GamePad;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IGamepadState>]
|
||||
#pragma warning restore SA1015
|
||||
public unsafe class GamepadState : IDisposable, IServiceType, IGamepadState
|
||||
internal unsafe class GamepadState : IDisposable, IServiceType, IGamepadState
|
||||
{
|
||||
private readonly Hook<ControllerPoll>? gamepadPoll;
|
||||
|
||||
|
|
@ -55,54 +55,6 @@ public unsafe class GamepadState : IDisposable, IServiceType, IGamepadState
|
|||
public Vector2 RightStick =>
|
||||
new(this.rightStickX, this.rightStickY);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of the left analogue stick in the left direction between 0 (not tilted) and 1 (max tilt).
|
||||
/// </summary>
|
||||
[Obsolete("Use IGamepadState.LeftStick.X", false)]
|
||||
public float LeftStickLeft => this.leftStickX < 0 ? -this.leftStickX / 100f : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of the left analogue stick in the right direction between 0 (not tilted) and 1 (max tilt).
|
||||
/// </summary>
|
||||
[Obsolete("Use IGamepadState.LeftStick.X", false)]
|
||||
public float LeftStickRight => this.leftStickX > 0 ? this.leftStickX / 100f : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of the left analogue stick in the up direction between 0 (not tilted) and 1 (max tilt).
|
||||
/// </summary>
|
||||
[Obsolete("Use IGamepadState.LeftStick.Y", false)]
|
||||
public float LeftStickUp => this.leftStickY > 0 ? this.leftStickY / 100f : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of the left analogue stick in the down direction between 0 (not tilted) and 1 (max tilt).
|
||||
/// </summary>
|
||||
[Obsolete("Use IGamepadState.LeftStick.Y", false)]
|
||||
public float LeftStickDown => this.leftStickY < 0 ? -this.leftStickY / 100f : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of the right analogue stick in the left direction between 0 (not tilted) and 1 (max tilt).
|
||||
/// </summary>
|
||||
[Obsolete("Use IGamepadState.RightStick.X", false)]
|
||||
public float RightStickLeft => this.rightStickX < 0 ? -this.rightStickX / 100f : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of the right analogue stick in the right direction between 0 (not tilted) and 1 (max tilt).
|
||||
/// </summary>
|
||||
[Obsolete("Use IGamepadState.RightStick.X", false)]
|
||||
public float RightStickRight => this.rightStickX > 0 ? this.rightStickX / 100f : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of the right analogue stick in the up direction between 0 (not tilted) and 1 (max tilt).
|
||||
/// </summary>
|
||||
[Obsolete("Use IGamepadState.RightStick.Y", false)]
|
||||
public float RightStickUp => this.rightStickY > 0 ? this.rightStickY / 100f : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of the right analogue stick in the down direction between 0 (not tilted) and 1 (max tilt).
|
||||
/// </summary>
|
||||
[Obsolete("Use IGamepadState.RightStick.Y", false)]
|
||||
public float RightStickDown => this.rightStickY < 0 ? -this.rightStickY / 100f : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets buttons pressed bitmask, set once when the button is pressed. See <see cref="GamepadButtons"/> for the mapping.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Dalamud.Game.ClientState.JobGauge;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IJobGauges>]
|
||||
#pragma warning restore SA1015
|
||||
public class JobGauges : IServiceType, IJobGauges
|
||||
internal class JobGauges : IServiceType, IJobGauges
|
||||
{
|
||||
private Dictionary<Type, JobGaugeBase> cache = new();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Keys;
|
||||
|
|
@ -23,7 +25,10 @@ namespace Dalamud.Game.ClientState.Keys;
|
|||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
public class KeyState : IServiceType
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IKeyState>]
|
||||
#pragma warning restore SA1015
|
||||
internal class KeyState : IServiceType, IKeyState
|
||||
{
|
||||
// The array is accessed in a way that this limit doesn't appear to exist
|
||||
// but there is other state data past this point, and keys beyond here aren't
|
||||
|
|
@ -31,10 +36,10 @@ public class KeyState : IServiceType
|
|||
private const int MaxKeyCode = 0xF0;
|
||||
private readonly IntPtr bufferBase;
|
||||
private readonly IntPtr indexBase;
|
||||
private VirtualKey[] validVirtualKeyCache = null;
|
||||
private VirtualKey[]? validVirtualKeyCache;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private KeyState(SigScanner sigScanner, ClientState clientState)
|
||||
private KeyState(TargetSigScanner sigScanner, ClientState clientState)
|
||||
{
|
||||
var moduleBaseAddress = sigScanner.Module.BaseAddress;
|
||||
var addressResolver = clientState.AddressResolver;
|
||||
|
|
@ -44,46 +49,29 @@ public class KeyState : IServiceType
|
|||
Log.Verbose($"Keyboard state buffer address 0x{this.bufferBase.ToInt64():X}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the key-pressed state for a given vkCode.
|
||||
/// </summary>
|
||||
/// <param name="vkCode">The virtual key to change.</param>
|
||||
/// <returns>Whether the specified key is currently pressed.</returns>
|
||||
/// <exception cref="ArgumentException">If the vkCode is not valid. Refer to <see cref="IsVirtualKeyValid(int)"/> or <see cref="GetValidVirtualKeys"/>.</exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">If the set value is non-zero.</exception>
|
||||
public unsafe bool this[int vkCode]
|
||||
/// <inheritdoc/>
|
||||
public bool this[int vkCode]
|
||||
{
|
||||
get => this.GetRawValue(vkCode) != 0;
|
||||
set => this.SetRawValue(vkCode, value ? 1 : 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="this[int]"/>
|
||||
/// <inheritdoc/>
|
||||
public bool this[VirtualKey vkCode]
|
||||
{
|
||||
get => this[(int)vkCode];
|
||||
set => this[(int)vkCode] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value in the index array.
|
||||
/// </summary>
|
||||
/// <param name="vkCode">The virtual key to change.</param>
|
||||
/// <returns>The raw value stored in the index array.</returns>
|
||||
/// <exception cref="ArgumentException">If the vkCode is not valid. Refer to <see cref="IsVirtualKeyValid(int)"/> or <see cref="GetValidVirtualKeys"/>.</exception>
|
||||
/// <inheritdoc/>
|
||||
public int GetRawValue(int vkCode)
|
||||
=> this.GetRefValue(vkCode);
|
||||
|
||||
/// <inheritdoc cref="GetRawValue(int)"/>
|
||||
/// <inheritdoc/>
|
||||
public int GetRawValue(VirtualKey vkCode)
|
||||
=> this.GetRawValue((int)vkCode);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value in the index array.
|
||||
/// </summary>
|
||||
/// <param name="vkCode">The virtual key to change.</param>
|
||||
/// <param name="value">The raw value to set in the index array.</param>
|
||||
/// <exception cref="ArgumentException">If the vkCode is not valid. Refer to <see cref="IsVirtualKeyValid(int)"/> or <see cref="GetValidVirtualKeys"/>.</exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">If the set value is non-zero.</exception>
|
||||
/// <inheritdoc/>
|
||||
public void SetRawValue(int vkCode, int value)
|
||||
{
|
||||
if (value != 0)
|
||||
|
|
@ -92,32 +80,23 @@ public class KeyState : IServiceType
|
|||
this.GetRefValue(vkCode) = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="SetRawValue(int, int)"/>
|
||||
/// <inheritdoc/>
|
||||
public void SetRawValue(VirtualKey vkCode, int value)
|
||||
=> this.SetRawValue((int)vkCode, value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the given VirtualKey code is regarded as valid input by the game.
|
||||
/// </summary>
|
||||
/// <param name="vkCode">Virtual key code.</param>
|
||||
/// <returns>If the code is valid.</returns>
|
||||
/// <inheritdoc/>
|
||||
public bool IsVirtualKeyValid(int vkCode)
|
||||
=> this.ConvertVirtualKey(vkCode) != 0;
|
||||
|
||||
/// <inheritdoc cref="IsVirtualKeyValid(int)"/>
|
||||
/// <inheritdoc/>
|
||||
public bool IsVirtualKeyValid(VirtualKey vkCode)
|
||||
=> this.IsVirtualKeyValid((int)vkCode);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an array of virtual keys the game considers valid input.
|
||||
/// </summary>
|
||||
/// <returns>An array of valid virtual keys.</returns>
|
||||
public VirtualKey[] GetValidVirtualKeys()
|
||||
=> this.validVirtualKeyCache ??= Enum.GetValues<VirtualKey>().Where(vk => this.IsVirtualKeyValid(vk)).ToArray();
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<VirtualKey> GetValidVirtualKeys()
|
||||
=> this.validVirtualKeyCache ??= Enum.GetValues<VirtualKey>().Where(this.IsVirtualKeyValid).ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// Clears the pressed state for all keys.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public void ClearAll()
|
||||
{
|
||||
foreach (var vk in this.GetValidVirtualKeys())
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Dalamud.Game.ClientState.Objects;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IObjectTable>]
|
||||
#pragma warning restore SA1015
|
||||
public sealed partial class ObjectTable : IServiceType, IObjectTable
|
||||
internal sealed partial class ObjectTable : IServiceType, IObjectTable
|
||||
{
|
||||
private const int ObjectTableLength = 596;
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ public sealed partial class ObjectTable : IServiceType, IObjectTable
|
|||
/// <summary>
|
||||
/// This collection represents the currently spawned FFXIV game objects.
|
||||
/// </summary>
|
||||
public sealed partial class ObjectTable
|
||||
internal sealed partial class ObjectTable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
int IReadOnlyCollection<GameObject>.Count => this.Length;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
using System;
|
||||
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Objects.Types;
|
||||
|
|
@ -25,5 +23,5 @@ public unsafe class BattleNpc : BattleChara
|
|||
public BattleNpcSubKind BattleNpcKind => (BattleNpcSubKind)this.Struct->Character.GameObject.SubKind;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override ulong TargetObjectId => this.Struct->Character.TargetObjectID;
|
||||
public override ulong TargetObjectId => this.Struct->Character.TargetId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
using System;
|
||||
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.ClientState.Resolvers;
|
||||
|
||||
|
|
@ -33,5 +31,5 @@ public unsafe class PlayerCharacter : BattleChara
|
|||
/// <summary>
|
||||
/// Gets the target actor ID of the PlayerCharacter.
|
||||
/// </summary>
|
||||
public override ulong TargetObjectId => this.Struct->Character.PlayerTargetObjectID;
|
||||
public override ulong TargetObjectId => this.Struct->Character.LookTargetId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Dalamud.Game.ClientState.Objects;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<ITargetManager>]
|
||||
#pragma warning restore SA1015
|
||||
public sealed unsafe class TargetManager : IServiceType, ITargetManager
|
||||
internal sealed unsafe class TargetManager : IServiceType, ITargetManager
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly ClientState clientState = Service<ClientState>.Get();
|
||||
|
|
@ -39,35 +39,35 @@ public sealed unsafe class TargetManager : IServiceType, ITargetManager
|
|||
public GameObject? Target
|
||||
{
|
||||
get => this.objectTable.CreateObjectReference((IntPtr)Struct->Target);
|
||||
set => this.SetTarget(value);
|
||||
set => Struct->Target = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public GameObject? MouseOverTarget
|
||||
{
|
||||
get => this.objectTable.CreateObjectReference((IntPtr)Struct->MouseOverTarget);
|
||||
set => this.SetMouseOverTarget(value);
|
||||
set => Struct->MouseOverTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public GameObject? FocusTarget
|
||||
{
|
||||
get => this.objectTable.CreateObjectReference((IntPtr)Struct->FocusTarget);
|
||||
set => this.SetFocusTarget(value);
|
||||
set => Struct->FocusTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public GameObject? PreviousTarget
|
||||
{
|
||||
get => this.objectTable.CreateObjectReference((IntPtr)Struct->PreviousTarget);
|
||||
set => this.SetPreviousTarget(value);
|
||||
set => Struct->PreviousTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public GameObject? SoftTarget
|
||||
{
|
||||
get => this.objectTable.CreateObjectReference((IntPtr)Struct->SoftTarget);
|
||||
set => this.SetSoftTarget(value);
|
||||
set => Struct->SoftTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
@ -85,104 +85,4 @@ public sealed unsafe class TargetManager : IServiceType, ITargetManager
|
|||
}
|
||||
|
||||
private FFXIVClientStructs.FFXIV.Client.Game.Control.TargetSystem* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Control.TargetSystem*)this.Address;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current target.
|
||||
/// </summary>
|
||||
/// <param name="actor">Actor to target.</param>
|
||||
[Obsolete("Use Target Property", false)]
|
||||
public void SetTarget(GameObject? actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the mouseover target.
|
||||
/// </summary>
|
||||
/// <param name="actor">Actor to target.</param>
|
||||
[Obsolete("Use MouseOverTarget Property", false)]
|
||||
public void SetMouseOverTarget(GameObject? actor) => this.SetMouseOverTarget(actor?.Address ?? IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the focus target.
|
||||
/// </summary>
|
||||
/// <param name="actor">Actor to target.</param>
|
||||
[Obsolete("Use FocusTarget Property", false)]
|
||||
public void SetFocusTarget(GameObject? actor) => this.SetFocusTarget(actor?.Address ?? IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the previous target.
|
||||
/// </summary>
|
||||
/// <param name="actor">Actor to target.</param>
|
||||
[Obsolete("Use PreviousTarget Property", false)]
|
||||
public void SetPreviousTarget(GameObject? actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the soft target.
|
||||
/// </summary>
|
||||
/// <param name="actor">Actor to target.</param>
|
||||
[Obsolete("Use SoftTarget Property", false)]
|
||||
public void SetSoftTarget(GameObject? actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current target.
|
||||
/// </summary>
|
||||
/// <param name="actorAddress">Actor (address) to target.</param>
|
||||
[Obsolete("Use Target Property", false)]
|
||||
public void SetTarget(IntPtr actorAddress) => Struct->Target = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)actorAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the mouseover target.
|
||||
/// </summary>
|
||||
/// <param name="actorAddress">Actor (address) to target.</param>
|
||||
[Obsolete("Use MouseOverTarget Property", false)]
|
||||
public void SetMouseOverTarget(IntPtr actorAddress) => Struct->MouseOverTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)actorAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the focus target.
|
||||
/// </summary>
|
||||
/// <param name="actorAddress">Actor (address) to target.</param>
|
||||
[Obsolete("Use FocusTarget Property", false)]
|
||||
public void SetFocusTarget(IntPtr actorAddress) => Struct->FocusTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)actorAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the previous target.
|
||||
/// </summary>
|
||||
/// <param name="actorAddress">Actor (address) to target.</param>
|
||||
[Obsolete("Use PreviousTarget Property", false)]
|
||||
public void SetPreviousTarget(IntPtr actorAddress) => Struct->PreviousTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)actorAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the soft target.
|
||||
/// </summary>
|
||||
/// <param name="actorAddress">Actor (address) to target.</param>
|
||||
[Obsolete("Use SoftTarget Property", false)]
|
||||
public void SetSoftTarget(IntPtr actorAddress) => Struct->SoftTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)actorAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Clears the current target.
|
||||
/// </summary>
|
||||
[Obsolete("Use Target Property", false)]
|
||||
public void ClearTarget() => this.SetTarget(IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the mouseover target.
|
||||
/// </summary>
|
||||
[Obsolete("Use MouseOverTarget Property", false)]
|
||||
public void ClearMouseOverTarget() => this.SetMouseOverTarget(IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the focus target.
|
||||
/// </summary>
|
||||
[Obsolete("Use FocusTarget Property", false)]
|
||||
public void ClearFocusTarget() => this.SetFocusTarget(IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the previous target.
|
||||
/// </summary>
|
||||
[Obsolete("Use PreviousTarget Property", false)]
|
||||
public void ClearPreviousTarget() => this.SetPreviousTarget(IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the soft target.
|
||||
/// </summary>
|
||||
[Obsolete("Use SoftTarget Property", false)]
|
||||
public void ClearSoftTarget() => this.SetSoftTarget(IntPtr.Zero);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
using System;
|
||||
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Game.ClientState.Resolvers;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
|
|
@ -87,7 +85,7 @@ public unsafe class Character : GameObject
|
|||
/// <summary>
|
||||
/// Gets the target object ID of the character.
|
||||
/// </summary>
|
||||
public override ulong TargetObjectId => this.Struct->TargetObjectID;
|
||||
public override ulong TargetObjectId => this.Struct->TargetId;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name ID of the character.
|
||||
|
|
@ -115,5 +113,6 @@ public unsafe class Character : GameObject
|
|||
/// <summary>
|
||||
/// Gets the underlying structure.
|
||||
/// </summary>
|
||||
protected internal new FFXIVClientStructs.FFXIV.Client.Game.Character.Character* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)this.Address;
|
||||
protected internal new FFXIVClientStructs.FFXIV.Client.Game.Character.Character* Struct =>
|
||||
(FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)this.Address;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Dalamud.Game.ClientState.Party;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IPartyList>]
|
||||
#pragma warning restore SA1015
|
||||
public sealed unsafe partial class PartyList : IServiceType, IPartyList
|
||||
internal sealed unsafe partial class PartyList : IServiceType, IPartyList
|
||||
{
|
||||
private const int GroupLength = 8;
|
||||
private const int AllianceLength = 20;
|
||||
|
|
@ -130,7 +130,7 @@ public sealed unsafe partial class PartyList : IServiceType, IPartyList
|
|||
/// <summary>
|
||||
/// This collection represents the party members present in your party or alliance.
|
||||
/// </summary>
|
||||
public sealed partial class PartyList
|
||||
internal sealed partial class PartyList
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
int IReadOnlyCollection<PartyMember>.Count => this.Length;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ public sealed class CommandInfo
|
|||
public CommandInfo(HandlerDelegate handler)
|
||||
{
|
||||
this.Handler = handler;
|
||||
this.LoaderAssemblyName = Assembly.GetCallingAssembly()?.GetName()?.Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
|
@ -9,22 +8,21 @@ using Dalamud.Game.Text;
|
|||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Logging.Internal;
|
||||
using Dalamud.Plugin.Internal.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Game.Command;
|
||||
|
||||
/// <summary>
|
||||
/// This class manages registered in-game slash commands.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<ICommandManager>]
|
||||
#pragma warning restore SA1015
|
||||
public sealed class CommandManager : IServiceType, IDisposable, ICommandManager
|
||||
internal sealed class CommandManager : IServiceType, IDisposable, ICommandManager
|
||||
{
|
||||
private static readonly ModuleLog Log = new("Command");
|
||||
|
||||
private readonly ConcurrentDictionary<string, CommandInfo> commandMap = new();
|
||||
private readonly Regex commandRegexEn = new(@"^The command (?<command>.+) does not exist\.$", RegexOptions.Compiled);
|
||||
private readonly Regex commandRegexJp = new(@"^そのコマンドはありません。: (?<command>.+)$", RegexOptions.Compiled);
|
||||
|
|
@ -37,15 +35,15 @@ public sealed class CommandManager : IServiceType, IDisposable, ICommandManager
|
|||
private readonly ChatGui chatGui = Service<ChatGui>.Get();
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private CommandManager(DalamudStartInfo startInfo)
|
||||
private CommandManager(Dalamud dalamud)
|
||||
{
|
||||
this.currentLangCommandRegex = startInfo.Language switch
|
||||
this.currentLangCommandRegex = (ClientLanguage)dalamud.StartInfo.Language switch
|
||||
{
|
||||
ClientLanguage.Japanese => this.commandRegexJp,
|
||||
ClientLanguage.English => this.commandRegexEn,
|
||||
ClientLanguage.German => this.commandRegexDe,
|
||||
ClientLanguage.French => this.commandRegexFr,
|
||||
_ => this.currentLangCommandRegex,
|
||||
_ => this.commandRegexEn,
|
||||
};
|
||||
|
||||
this.chatGui.CheckMessageHandled += this.OnCheckMessageHandled;
|
||||
|
|
@ -84,7 +82,7 @@ public sealed class CommandManager : IServiceType, IDisposable, ICommandManager
|
|||
// => command: 0-12 (12 chars)
|
||||
// => argument: 13-17 (4 chars)
|
||||
// => content.IndexOf(' ') == 12
|
||||
command = content.Substring(0, separatorPosition);
|
||||
command = content[..separatorPosition];
|
||||
|
||||
var argStart = separatorPosition + 1;
|
||||
argument = content[argStart..];
|
||||
|
|
@ -162,3 +160,93 @@ public sealed class CommandManager : IServiceType, IDisposable, ICommandManager
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plugin-scoped version of a AddonLifecycle service.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.ScopedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<ICommandManager>]
|
||||
#pragma warning restore SA1015
|
||||
internal class CommandManagerPluginScoped : IDisposable, IServiceType, ICommandManager
|
||||
{
|
||||
private static readonly ModuleLog Log = new("Command");
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly CommandManager commandManagerService = Service<CommandManager>.Get();
|
||||
|
||||
private readonly List<string> pluginRegisteredCommands = new();
|
||||
private readonly LocalPlugin pluginInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CommandManagerPluginScoped"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localPlugin">Info for the plugin that requests this service.</param>
|
||||
public CommandManagerPluginScoped(LocalPlugin localPlugin)
|
||||
{
|
||||
this.pluginInfo = localPlugin;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ReadOnlyDictionary<string, CommandInfo> Commands => this.commandManagerService.Commands;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var command in this.pluginRegisteredCommands)
|
||||
{
|
||||
this.commandManagerService.RemoveHandler(command);
|
||||
}
|
||||
|
||||
this.pluginRegisteredCommands.Clear();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool ProcessCommand(string content)
|
||||
=> this.commandManagerService.ProcessCommand(content);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void DispatchCommand(string command, string argument, CommandInfo info)
|
||||
=> this.commandManagerService.DispatchCommand(command, argument, info);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool AddHandler(string command, CommandInfo info)
|
||||
{
|
||||
if (!this.pluginRegisteredCommands.Contains(command))
|
||||
{
|
||||
info.LoaderAssemblyName = this.pluginInfo.InternalName;
|
||||
if (this.commandManagerService.AddHandler(command, info))
|
||||
{
|
||||
this.pluginRegisteredCommands.Add(command);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Command {command} is already registered.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool RemoveHandler(string command)
|
||||
{
|
||||
if (this.pluginRegisteredCommands.Contains(command))
|
||||
{
|
||||
if (this.commandManagerService.RemoveHandler(command))
|
||||
{
|
||||
this.pluginRegisteredCommands.Remove(command);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Command {command} not found.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
|
|
@ -13,18 +12,14 @@ namespace Dalamud.Game.Config;
|
|||
/// This class represents the game's configuration.
|
||||
/// </summary>
|
||||
[InterfaceVersion("1.0")]
|
||||
[PluginInterface]
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IGameConfig>]
|
||||
#pragma warning restore SA1015
|
||||
public sealed class GameConfig : IServiceType, IGameConfig, IDisposable
|
||||
internal sealed class GameConfig : IServiceType, IGameConfig, IDisposable
|
||||
{
|
||||
private readonly GameConfigAddressResolver address = new();
|
||||
private Hook<ConfigChangeDelegate>? configChangeHook;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private unsafe GameConfig(Framework framework, SigScanner sigScanner)
|
||||
private unsafe GameConfig(Framework framework, TargetSigScanner sigScanner)
|
||||
{
|
||||
framework.RunOnTick(() =>
|
||||
{
|
||||
|
|
@ -37,15 +32,32 @@ public sealed class GameConfig : IServiceType, IGameConfig, IDisposable
|
|||
|
||||
this.address.Setup(sigScanner);
|
||||
this.configChangeHook = Hook<ConfigChangeDelegate>.FromAddress(this.address.ConfigChangeAddress, this.OnConfigChanged);
|
||||
this.configChangeHook?.Enable();
|
||||
this.configChangeHook.Enable();
|
||||
});
|
||||
}
|
||||
|
||||
private unsafe delegate nint ConfigChangeDelegate(ConfigBase* configBase, ConfigEntry* configEntry);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ConfigChangeEvent> Changed;
|
||||
public event EventHandler<ConfigChangeEvent>? Changed;
|
||||
|
||||
#pragma warning disable 67
|
||||
/// <summary>
|
||||
/// Unused internally, used as a proxy for System.Changed via GameConfigPluginScoped
|
||||
/// </summary>
|
||||
public event EventHandler<ConfigChangeEvent>? SystemChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Unused internally, used as a proxy for UiConfig.Changed via GameConfigPluginScoped
|
||||
/// </summary>
|
||||
public event EventHandler<ConfigChangeEvent>? UiConfigChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Unused internally, used as a proxy for UiControl.Changed via GameConfigPluginScoped
|
||||
/// </summary>
|
||||
public event EventHandler<ConfigChangeEvent>? UiControlChanged;
|
||||
#pragma warning restore 67
|
||||
|
||||
/// <inheritdoc/>
|
||||
public GameConfigSection System { get; private set; }
|
||||
|
||||
|
|
@ -193,3 +205,204 @@ public sealed class GameConfig : IServiceType, IGameConfig, IDisposable
|
|||
return returnValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plugin-scoped version of a GameConfig service.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.ScopedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IGameConfig>]
|
||||
#pragma warning restore SA1015
|
||||
internal class GameConfigPluginScoped : IDisposable, IServiceType, IGameConfig
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly GameConfig gameConfigService = Service<GameConfig>.Get();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameConfigPluginScoped"/> class.
|
||||
/// </summary>
|
||||
internal GameConfigPluginScoped()
|
||||
{
|
||||
this.gameConfigService.Changed += this.ConfigChangedForward;
|
||||
this.gameConfigService.System.Changed += this.SystemConfigChangedForward;
|
||||
this.gameConfigService.UiConfig.Changed += this.UiConfigConfigChangedForward;
|
||||
this.gameConfigService.UiControl.Changed += this.UiControlConfigChangedForward;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ConfigChangeEvent>? Changed;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ConfigChangeEvent>? SystemChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ConfigChangeEvent>? UiConfigChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ConfigChangeEvent>? UiControlChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public GameConfigSection System => this.gameConfigService.System;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public GameConfigSection UiConfig => this.gameConfigService.UiConfig;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public GameConfigSection UiControl => this.gameConfigService.UiControl;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.gameConfigService.Changed -= this.ConfigChangedForward;
|
||||
this.gameConfigService.System.Changed -= this.SystemConfigChangedForward;
|
||||
this.gameConfigService.UiConfig.Changed -= this.UiConfigConfigChangedForward;
|
||||
this.gameConfigService.UiControl.Changed -= this.UiControlConfigChangedForward;
|
||||
|
||||
this.Changed = null;
|
||||
this.SystemChanged = null;
|
||||
this.UiConfigChanged = null;
|
||||
this.UiControlChanged = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(SystemConfigOption option, out bool value)
|
||||
=> this.gameConfigService.TryGet(option, out value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(SystemConfigOption option, out uint value)
|
||||
=> this.gameConfigService.TryGet(option, out value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(SystemConfigOption option, out float value)
|
||||
=> this.gameConfigService.TryGet(option, out value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(SystemConfigOption option, out string value)
|
||||
=> this.gameConfigService.TryGet(option, out value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(SystemConfigOption option, out UIntConfigProperties? properties)
|
||||
=> this.gameConfigService.TryGet(option, out properties);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(SystemConfigOption option, out FloatConfigProperties? properties)
|
||||
=> this.gameConfigService.TryGet(option, out properties);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(SystemConfigOption option, out StringConfigProperties? properties)
|
||||
=> this.gameConfigService.TryGet(option, out properties);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(UiConfigOption option, out bool value)
|
||||
=> this.gameConfigService.TryGet(option, out value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(UiConfigOption option, out uint value)
|
||||
=> this.gameConfigService.TryGet(option, out value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(UiConfigOption option, out float value)
|
||||
=> this.gameConfigService.TryGet(option, out value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(UiConfigOption option, out string value)
|
||||
=> this.gameConfigService.TryGet(option, out value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(UiConfigOption option, out UIntConfigProperties? properties)
|
||||
=> this.gameConfigService.TryGet(option, out properties);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(UiConfigOption option, out FloatConfigProperties? properties)
|
||||
=> this.gameConfigService.TryGet(option, out properties);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(UiConfigOption option, out StringConfigProperties? properties)
|
||||
=> this.gameConfigService.TryGet(option, out properties);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(UiControlOption option, out bool value)
|
||||
=> this.gameConfigService.TryGet(option, out value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(UiControlOption option, out uint value)
|
||||
=> this.gameConfigService.TryGet(option, out value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(UiControlOption option, out float value)
|
||||
=> this.gameConfigService.TryGet(option, out value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(UiControlOption option, out string value)
|
||||
=> this.gameConfigService.TryGet(option, out value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(UiControlOption option, out UIntConfigProperties? properties)
|
||||
=> this.gameConfigService.TryGet(option, out properties);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(UiControlOption option, out FloatConfigProperties? properties)
|
||||
=> this.gameConfigService.TryGet(option, out properties);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGet(UiControlOption option, out StringConfigProperties? properties)
|
||||
=> this.gameConfigService.TryGet(option, out properties);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Set(SystemConfigOption option, bool value)
|
||||
=> this.gameConfigService.Set(option, value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Set(SystemConfigOption option, uint value)
|
||||
=> this.gameConfigService.Set(option, value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Set(SystemConfigOption option, float value)
|
||||
=> this.gameConfigService.Set(option, value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Set(SystemConfigOption option, string value)
|
||||
=> this.gameConfigService.Set(option, value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Set(UiConfigOption option, bool value)
|
||||
=> this.gameConfigService.Set(option, value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Set(UiConfigOption option, uint value)
|
||||
=> this.gameConfigService.Set(option, value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Set(UiConfigOption option, float value)
|
||||
=> this.gameConfigService.Set(option, value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Set(UiConfigOption option, string value)
|
||||
=> this.gameConfigService.Set(option, value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Set(UiControlOption option, bool value)
|
||||
=> this.gameConfigService.Set(option, value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Set(UiControlOption option, uint value)
|
||||
=> this.gameConfigService.Set(option, value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Set(UiControlOption option, float value)
|
||||
=> this.gameConfigService.Set(option, value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Set(UiControlOption option, string value)
|
||||
=> this.gameConfigService.Set(option, value);
|
||||
|
||||
private void ConfigChangedForward(object sender, ConfigChangeEvent data) => this.Changed?.Invoke(sender, data);
|
||||
|
||||
private void SystemConfigChangedForward(object sender, ConfigChangeEvent data) => this.SystemChanged?.Invoke(sender, data);
|
||||
|
||||
private void UiConfigConfigChangedForward(object sender, ConfigChangeEvent data) => this.UiConfigChanged?.Invoke(sender, data);
|
||||
|
||||
private void UiControlConfigChangedForward(object sender, ConfigChangeEvent data) => this.UiControlChanged?.Invoke(sender, data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
/// <summary>
|
||||
/// Game config system address resolver.
|
||||
/// </summary>
|
||||
public sealed class GameConfigAddressResolver : BaseAddressResolver
|
||||
internal sealed class GameConfigAddressResolver : BaseAddressResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the address of the method called when any config option is changed.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
|
||||
using Dalamud.Memory;
|
||||
|
|
@ -18,11 +17,6 @@ public class GameConfigSection
|
|||
private readonly ConcurrentDictionary<string, uint> indexMap = new();
|
||||
private readonly ConcurrentDictionary<uint, object> enumMap = new();
|
||||
|
||||
/// <summary>
|
||||
/// Event which is fired when a game config option is changed within the section.
|
||||
/// </summary>
|
||||
public event EventHandler<ConfigChangeEvent> Changed;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameConfigSection"/> class.
|
||||
/// </summary>
|
||||
|
|
@ -54,6 +48,11 @@ public class GameConfigSection
|
|||
/// <returns>Pointer to unmanaged ConfigBase.</returns>
|
||||
internal unsafe delegate ConfigBase* GetConfigBaseDelegate();
|
||||
|
||||
/// <summary>
|
||||
/// Event which is fired when a game config option is changed within the section.
|
||||
/// </summary>
|
||||
internal event EventHandler<ConfigChangeEvent>? Changed;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of config entries contained within the section.
|
||||
/// Some entries may be empty with no data.
|
||||
|
|
|
|||
|
|
@ -1,25 +1,19 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
|
||||
namespace Dalamud.Game.DutyState;
|
||||
|
||||
/// <summary>
|
||||
/// This class represents the state of the currently occupied duty.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IDutyState>]
|
||||
#pragma warning restore SA1015
|
||||
public unsafe class DutyState : IDisposable, IServiceType, IDutyState
|
||||
internal unsafe class DutyState : IDisposable, IServiceType, IDutyState
|
||||
{
|
||||
private readonly DutyStateAddressResolver address;
|
||||
private readonly Hook<SetupContentDirectNetworkMessageDelegate> contentDirectorNetworkMessageHook;
|
||||
|
|
@ -34,7 +28,7 @@ public unsafe class DutyState : IDisposable, IServiceType, IDutyState
|
|||
private readonly ClientState.ClientState clientState = Service<ClientState.ClientState>.Get();
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private DutyState(SigScanner sigScanner)
|
||||
private DutyState(TargetSigScanner sigScanner)
|
||||
{
|
||||
this.address = new DutyStateAddressResolver();
|
||||
this.address.Setup(sigScanner);
|
||||
|
|
@ -49,16 +43,16 @@ public unsafe class DutyState : IDisposable, IServiceType, IDutyState
|
|||
private delegate byte SetupContentDirectNetworkMessageDelegate(IntPtr a1, IntPtr a2, ushort* a3);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ushort> DutyStarted;
|
||||
public event EventHandler<ushort>? DutyStarted;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ushort> DutyWiped;
|
||||
public event EventHandler<ushort>? DutyWiped;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ushort> DutyRecommenced;
|
||||
public event EventHandler<ushort>? DutyRecommenced;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ushort> DutyCompleted;
|
||||
public event EventHandler<ushort>? DutyCompleted;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsDutyStarted { get; private set; }
|
||||
|
|
@ -66,7 +60,7 @@ public unsafe class DutyState : IDisposable, IServiceType, IDutyState
|
|||
private bool CompletedThisTerritory { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IDisposable.Dispose()
|
||||
public void Dispose()
|
||||
{
|
||||
this.contentDirectorNetworkMessageHook.Dispose();
|
||||
this.framework.Update -= this.FrameworkOnUpdateEvent;
|
||||
|
|
@ -92,33 +86,33 @@ public unsafe class DutyState : IDisposable, IServiceType, IDutyState
|
|||
// Duty Commenced
|
||||
case 0x4000_0001:
|
||||
this.IsDutyStarted = true;
|
||||
this.DutyStarted.InvokeSafely(this, this.clientState.TerritoryType);
|
||||
this.DutyStarted?.Invoke(this, this.clientState.TerritoryType);
|
||||
break;
|
||||
|
||||
// Party Wipe
|
||||
case 0x4000_0005:
|
||||
this.IsDutyStarted = false;
|
||||
this.DutyWiped.InvokeSafely(this, this.clientState.TerritoryType);
|
||||
this.DutyWiped?.Invoke(this, this.clientState.TerritoryType);
|
||||
break;
|
||||
|
||||
// Duty Recommence
|
||||
case 0x4000_0006:
|
||||
this.IsDutyStarted = true;
|
||||
this.DutyRecommenced.InvokeSafely(this, this.clientState.TerritoryType);
|
||||
this.DutyRecommenced?.Invoke(this, this.clientState.TerritoryType);
|
||||
break;
|
||||
|
||||
// Duty Completed Flytext Shown
|
||||
case 0x4000_0002 when !this.CompletedThisTerritory:
|
||||
this.IsDutyStarted = false;
|
||||
this.CompletedThisTerritory = true;
|
||||
this.DutyCompleted.InvokeSafely(this, this.clientState.TerritoryType);
|
||||
this.DutyCompleted?.Invoke(this, this.clientState.TerritoryType);
|
||||
break;
|
||||
|
||||
// Duty Completed
|
||||
case 0x4000_0003 when !this.CompletedThisTerritory:
|
||||
this.IsDutyStarted = false;
|
||||
this.CompletedThisTerritory = true;
|
||||
this.DutyCompleted.InvokeSafely(this, this.clientState.TerritoryType);
|
||||
this.DutyCompleted?.Invoke(this, this.clientState.TerritoryType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -126,7 +120,7 @@ public unsafe class DutyState : IDisposable, IServiceType, IDutyState
|
|||
return this.contentDirectorNetworkMessageHook.Original(a1, a2, a3);
|
||||
}
|
||||
|
||||
private void TerritoryOnChangedEvent(object? sender, ushort e)
|
||||
private void TerritoryOnChangedEvent(ushort territoryId)
|
||||
{
|
||||
if (this.IsDutyStarted)
|
||||
{
|
||||
|
|
@ -141,7 +135,7 @@ public unsafe class DutyState : IDisposable, IServiceType, IDutyState
|
|||
/// Joining a duty in progress, or disconnecting and reconnecting will cause the player to miss the event.
|
||||
/// </summary>
|
||||
/// <param name="framework1">Framework reference.</param>
|
||||
private void FrameworkOnUpdateEvent(Framework framework1)
|
||||
private void FrameworkOnUpdateEvent(IFramework framework1)
|
||||
{
|
||||
// If the duty hasn't been started, and has not been completed yet this territory
|
||||
if (!this.IsDutyStarted && !this.CompletedThisTerritory)
|
||||
|
|
@ -161,11 +155,73 @@ public unsafe class DutyState : IDisposable, IServiceType, IDutyState
|
|||
}
|
||||
|
||||
private bool IsBoundByDuty()
|
||||
=> this.condition.Any(ConditionFlag.BoundByDuty,
|
||||
ConditionFlag.BoundByDuty56,
|
||||
ConditionFlag.BoundByDuty95);
|
||||
|
||||
private bool IsInCombat()
|
||||
=> this.condition.Any(ConditionFlag.InCombat);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plugin scoped version of DutyState.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.ScopedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IDutyState>]
|
||||
#pragma warning restore SA1015
|
||||
internal class DutyStatePluginScoped : IDisposable, IServiceType, IDutyState
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly DutyState dutyStateService = Service<DutyState>.Get();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DutyStatePluginScoped"/> class.
|
||||
/// </summary>
|
||||
internal DutyStatePluginScoped()
|
||||
{
|
||||
return this.condition[ConditionFlag.BoundByDuty] ||
|
||||
this.condition[ConditionFlag.BoundByDuty56] ||
|
||||
this.condition[ConditionFlag.BoundByDuty95];
|
||||
this.dutyStateService.DutyStarted += this.DutyStartedForward;
|
||||
this.dutyStateService.DutyWiped += this.DutyWipedForward;
|
||||
this.dutyStateService.DutyRecommenced += this.DutyRecommencedForward;
|
||||
this.dutyStateService.DutyCompleted += this.DutyCompletedForward;
|
||||
}
|
||||
|
||||
private bool IsInCombat() => this.condition[ConditionFlag.InCombat];
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ushort>? DutyStarted;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ushort>? DutyWiped;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ushort>? DutyRecommenced;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ushort>? DutyCompleted;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsDutyStarted => this.dutyStateService.IsDutyStarted;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.dutyStateService.DutyStarted -= this.DutyStartedForward;
|
||||
this.dutyStateService.DutyWiped -= this.DutyWipedForward;
|
||||
this.dutyStateService.DutyRecommenced -= this.DutyRecommencedForward;
|
||||
this.dutyStateService.DutyCompleted -= this.DutyCompletedForward;
|
||||
|
||||
this.DutyStarted = null;
|
||||
this.DutyWiped = null;
|
||||
this.DutyRecommenced = null;
|
||||
this.DutyCompleted = null;
|
||||
}
|
||||
|
||||
private void DutyStartedForward(object sender, ushort territoryId) => this.DutyStarted?.Invoke(sender, territoryId);
|
||||
|
||||
private void DutyWipedForward(object sender, ushort territoryId) => this.DutyWiped?.Invoke(sender, territoryId);
|
||||
|
||||
private void DutyRecommencedForward(object sender, ushort territoryId) => this.DutyRecommenced?.Invoke(sender, territoryId);
|
||||
|
||||
private void DutyCompletedForward(object sender, ushort territoryId) => this.DutyCompleted?.Invoke(sender, territoryId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.Game.DutyState;
|
||||
|
||||
/// <summary>
|
||||
/// Duty state memory address resolver.
|
||||
/// </summary>
|
||||
public class DutyStateAddressResolver : BaseAddressResolver
|
||||
internal class DutyStateAddressResolver : BaseAddressResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the address of the method which is called when the client receives a content director update.
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ using Dalamud.Game.Gui.Toast;
|
|||
using Dalamud.Hooking;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
using Serilog;
|
||||
|
||||
|
|
@ -23,7 +24,10 @@ namespace Dalamud.Game;
|
|||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
public sealed class Framework : IDisposable, IServiceType
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IFramework>]
|
||||
#pragma warning restore SA1015
|
||||
internal sealed class Framework : IDisposable, IServiceType, IFramework
|
||||
{
|
||||
private static readonly Stopwatch StatsStopwatch = new();
|
||||
|
||||
|
|
@ -35,6 +39,8 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
private readonly Hook<OnUpdateDetour> updateHook;
|
||||
private readonly Hook<OnRealDestroyDelegate> destroyHook;
|
||||
|
||||
private readonly FrameworkAddressResolver addressResolver;
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly DalamudConfiguration configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
|
|
@ -45,24 +51,18 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
private Thread? frameworkUpdateThread;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private Framework(SigScanner sigScanner, GameLifecycle lifecycle)
|
||||
private Framework(TargetSigScanner sigScanner, GameLifecycle lifecycle)
|
||||
{
|
||||
this.lifecycle = lifecycle;
|
||||
this.hitchDetector = new HitchDetector("FrameworkUpdate", this.configuration.FrameworkUpdateHitch);
|
||||
|
||||
this.Address = new FrameworkAddressResolver();
|
||||
this.Address.Setup(sigScanner);
|
||||
this.addressResolver = new FrameworkAddressResolver();
|
||||
this.addressResolver.Setup(sigScanner);
|
||||
|
||||
this.updateHook = Hook<OnUpdateDetour>.FromAddress(this.Address.TickAddress, this.HandleFrameworkUpdate);
|
||||
this.destroyHook = Hook<OnRealDestroyDelegate>.FromAddress(this.Address.DestroyAddress, this.HandleFrameworkDestroy);
|
||||
this.updateHook = Hook<OnUpdateDetour>.FromAddress(this.addressResolver.TickAddress, this.HandleFrameworkUpdate);
|
||||
this.destroyHook = Hook<OnRealDestroyDelegate>.FromAddress(this.addressResolver.DestroyAddress, this.HandleFrameworkDestroy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A delegate type used with the <see cref="Update"/> event.
|
||||
/// </summary>
|
||||
/// <param name="framework">The Framework instance.</param>
|
||||
public delegate void OnUpdateDelegate(Framework framework);
|
||||
|
||||
/// <summary>
|
||||
/// A delegate type used during the native Framework::destroy.
|
||||
/// </summary>
|
||||
|
|
@ -81,10 +81,8 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
|
||||
private delegate IntPtr OnDestroyDetour(); // OnDestroyDelegate
|
||||
|
||||
/// <summary>
|
||||
/// Event that gets fired every time the game framework updates.
|
||||
/// </summary>
|
||||
public event OnUpdateDelegate Update;
|
||||
/// <inheritdoc/>
|
||||
public event IFramework.OnUpdateDelegate Update;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the collection of stats is enabled.
|
||||
|
|
@ -96,34 +94,19 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
/// </summary>
|
||||
public static Dictionary<string, List<double>> StatsHistory { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a raw pointer to the instance of Client::Framework.
|
||||
/// </summary>
|
||||
public FrameworkAddressResolver Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last time that the Framework Update event was triggered.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastUpdate { get; private set; } = DateTime.MinValue;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last time in UTC that the Framework Update event was triggered.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastUpdateUTC { get; private set; } = DateTime.MinValue;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the delta between the last Framework Update and the currently executing one.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public TimeSpan UpdateDelta { get; private set; } = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether currently executing code is running in the game's framework update thread.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public bool IsInFrameworkUpdateThread => Thread.CurrentThread == this.frameworkUpdateThread;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether game Framework is unloading.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public bool IsFrameworkUnloading { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -131,20 +114,11 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
/// </summary>
|
||||
internal bool DispatchUpdateEvents { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Run given function right away if this function has been called from game's Framework.Update thread, or otherwise run on next Framework.Update call.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Return type.</typeparam>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <returns>Task representing the pending or already completed function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task<T> RunOnFrameworkThread<T>(Func<T> func) =>
|
||||
this.IsInFrameworkUpdateThread || this.IsFrameworkUnloading ? Task.FromResult(func()) : this.RunOnTick(func);
|
||||
|
||||
/// <summary>
|
||||
/// Run given function right away if this function has been called from game's Framework.Update thread, or otherwise run on next Framework.Update call.
|
||||
/// </summary>
|
||||
/// <param name="action">Function to call.</param>
|
||||
/// <returns>Task representing the pending or already completed function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task RunOnFrameworkThread(Action action)
|
||||
{
|
||||
if (this.IsInFrameworkUpdateThread || this.IsFrameworkUnloading)
|
||||
|
|
@ -165,32 +139,15 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run given function right away if this function has been called from game's Framework.Update thread, or otherwise run on next Framework.Update call.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Return type.</typeparam>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <returns>Task representing the pending or already completed function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task<T> RunOnFrameworkThread<T>(Func<Task<T>> func) =>
|
||||
this.IsInFrameworkUpdateThread || this.IsFrameworkUnloading ? func() : this.RunOnTick(func);
|
||||
|
||||
/// <summary>
|
||||
/// Run given function right away if this function has been called from game's Framework.Update thread, or otherwise run on next Framework.Update call.
|
||||
/// </summary>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <returns>Task representing the pending or already completed function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task RunOnFrameworkThread(Func<Task> func) =>
|
||||
this.IsInFrameworkUpdateThread || this.IsFrameworkUnloading ? func() : this.RunOnTick(func);
|
||||
|
||||
/// <summary>
|
||||
/// Run given function in upcoming Framework.Tick call.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Return type.</typeparam>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <param name="delay">Wait for given timespan before calling this function.</param>
|
||||
/// <param name="delayTicks">Count given number of Framework.Tick calls before calling this function. This takes precedence over delay parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token which will prevent the execution of this function if wait conditions are not met.</param>
|
||||
/// <returns>Task representing the pending function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task<T> RunOnTick<T>(Func<T> func, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (this.IsFrameworkUnloading)
|
||||
|
|
@ -219,14 +176,7 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
return tcs.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run given function in upcoming Framework.Tick call.
|
||||
/// </summary>
|
||||
/// <param name="action">Function to call.</param>
|
||||
/// <param name="delay">Wait for given timespan before calling this function.</param>
|
||||
/// <param name="delayTicks">Count given number of Framework.Tick calls before calling this function. This takes precedence over delay parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token which will prevent the execution of this function if wait conditions are not met.</param>
|
||||
/// <returns>Task representing the pending function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task RunOnTick(Action action, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (this.IsFrameworkUnloading)
|
||||
|
|
@ -255,15 +205,7 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
return tcs.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run given function in upcoming Framework.Tick call.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Return type.</typeparam>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <param name="delay">Wait for given timespan before calling this function.</param>
|
||||
/// <param name="delayTicks">Count given number of Framework.Tick calls before calling this function. This takes precedence over delay parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token which will prevent the execution of this function if wait conditions are not met.</param>
|
||||
/// <returns>Task representing the pending function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task<T> RunOnTick<T>(Func<Task<T>> func, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (this.IsFrameworkUnloading)
|
||||
|
|
@ -292,14 +234,7 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
return tcs.Task.ContinueWith(x => x.Result, cancellationToken).Unwrap();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run given function in upcoming Framework.Tick call.
|
||||
/// </summary>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <param name="delay">Wait for given timespan before calling this function.</param>
|
||||
/// <param name="delayTicks">Count given number of Framework.Tick calls before calling this function. This takes precedence over delay parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token which will prevent the execution of this function if wait conditions are not met.</param>
|
||||
/// <returns>Task representing the pending function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task RunOnTick(Func<Task> func, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (this.IsFrameworkUnloading)
|
||||
|
|
|
|||
|
|
@ -5,14 +5,8 @@ namespace Dalamud.Game;
|
|||
/// <summary>
|
||||
/// The address resolver for the <see cref="Framework"/> class.
|
||||
/// </summary>
|
||||
public sealed unsafe class FrameworkAddressResolver : BaseAddressResolver
|
||||
internal sealed class FrameworkAddressResolver : BaseAddressResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the base address of the Framework object.
|
||||
/// </summary>
|
||||
[Obsolete("Please use FFXIVClientStructs.FFXIV.Client.System.Framework.Framework.Instance() instead.")]
|
||||
public IntPtr BaseAddress => new(FFXIVClientStructs.FFXIV.Client.System.Framework.Framework.Instance());
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address for the function that is called once the Framework is destroyed.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace Dalamud.Game;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IGameLifecycle>]
|
||||
#pragma warning restore SA1015
|
||||
public class GameLifecycle : IServiceType, IGameLifecycle
|
||||
internal class GameLifecycle : IServiceType, IGameLifecycle
|
||||
{
|
||||
private readonly CancellationTokenSource dalamudUnloadCts = new();
|
||||
private readonly CancellationTokenSource gameShutdownCts = new();
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ using Dalamud.Game.Text.SeStringHandling.Payloads;
|
|||
using Dalamud.Hooking;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
using Serilog;
|
||||
|
||||
|
|
@ -19,10 +20,9 @@ namespace Dalamud.Game.Gui;
|
|||
/// <summary>
|
||||
/// This class handles interacting with the native chat UI.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
public sealed class ChatGui : IDisposable, IServiceType
|
||||
internal sealed class ChatGui : IDisposable, IServiceType, IChatGui
|
||||
{
|
||||
private readonly ChatGuiAddressResolver address;
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ public sealed class ChatGui : IDisposable, IServiceType
|
|||
private IntPtr baseAddress = IntPtr.Zero;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private ChatGui(SigScanner sigScanner)
|
||||
private ChatGui(TargetSigScanner sigScanner)
|
||||
{
|
||||
this.address = new ChatGuiAddressResolver();
|
||||
this.address.Setup(sigScanner);
|
||||
|
|
@ -51,45 +51,7 @@ public sealed class ChatGui : IDisposable, IServiceType
|
|||
this.populateItemLinkHook = Hook<PopulateItemLinkDelegate>.FromAddress(this.address.PopulateItemLinkObject, this.HandlePopulateItemLinkDetour);
|
||||
this.interactableLinkClickedHook = Hook<InteractableLinkClickedDelegate>.FromAddress(this.address.InteractableLinkClicked, this.InteractableLinkClickedDetour);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A delegate type used with the <see cref="ChatGui.ChatMessage"/> event.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of chat.</param>
|
||||
/// <param name="senderId">The sender ID.</param>
|
||||
/// <param name="sender">The sender name.</param>
|
||||
/// <param name="message">The message sent.</param>
|
||||
/// <param name="isHandled">A value indicating whether the message was handled or should be propagated.</param>
|
||||
public delegate void OnMessageDelegate(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled);
|
||||
|
||||
/// <summary>
|
||||
/// A delegate type used with the <see cref="ChatGui.CheckMessageHandled"/> event.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of chat.</param>
|
||||
/// <param name="senderId">The sender ID.</param>
|
||||
/// <param name="sender">The sender name.</param>
|
||||
/// <param name="message">The message sent.</param>
|
||||
/// <param name="isHandled">A value indicating whether the message was handled or should be propagated.</param>
|
||||
public delegate void OnCheckMessageHandledDelegate(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled);
|
||||
|
||||
/// <summary>
|
||||
/// A delegate type used with the <see cref="ChatGui.ChatMessageHandled"/> event.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of chat.</param>
|
||||
/// <param name="senderId">The sender ID.</param>
|
||||
/// <param name="sender">The sender name.</param>
|
||||
/// <param name="message">The message sent.</param>
|
||||
public delegate void OnMessageHandledDelegate(XivChatType type, uint senderId, SeString sender, SeString message);
|
||||
|
||||
/// <summary>
|
||||
/// A delegate type used with the <see cref="ChatGui.ChatMessageUnhandled"/> event.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of chat.</param>
|
||||
/// <param name="senderId">The sender ID.</param>
|
||||
/// <param name="sender">The sender name.</param>
|
||||
/// <param name="message">The message sent.</param>
|
||||
public delegate void OnMessageUnhandledDelegate(XivChatType type, uint senderId, SeString sender, SeString message);
|
||||
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
private delegate IntPtr PrintMessageDelegate(IntPtr manager, XivChatType chatType, IntPtr senderName, IntPtr message, uint senderId, IntPtr parameter);
|
||||
|
||||
|
|
@ -99,34 +61,22 @@ public sealed class ChatGui : IDisposable, IServiceType
|
|||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
private delegate void InteractableLinkClickedDelegate(IntPtr managerPtr, IntPtr messagePtr);
|
||||
|
||||
/// <summary>
|
||||
/// Event that will be fired when a chat message is sent to chat by the game.
|
||||
/// </summary>
|
||||
public event OnMessageDelegate ChatMessage;
|
||||
/// <inheritdoc/>
|
||||
public event IChatGui.OnMessageDelegate? ChatMessage;
|
||||
|
||||
/// <summary>
|
||||
/// Event that allows you to stop messages from appearing in chat by setting the isHandled parameter to true.
|
||||
/// </summary>
|
||||
public event OnCheckMessageHandledDelegate CheckMessageHandled;
|
||||
/// <inheritdoc/>
|
||||
public event IChatGui.OnCheckMessageHandledDelegate? CheckMessageHandled;
|
||||
|
||||
/// <summary>
|
||||
/// Event that will be fired when a chat message is handled by Dalamud or a Plugin.
|
||||
/// </summary>
|
||||
public event OnMessageHandledDelegate ChatMessageHandled;
|
||||
/// <inheritdoc/>
|
||||
public event IChatGui.OnMessageHandledDelegate? ChatMessageHandled;
|
||||
|
||||
/// <summary>
|
||||
/// Event that will be fired when a chat message is not handled by Dalamud or a Plugin.
|
||||
/// </summary>
|
||||
public event OnMessageUnhandledDelegate ChatMessageUnhandled;
|
||||
/// <inheritdoc/>
|
||||
public event IChatGui.OnMessageUnhandledDelegate? ChatMessageUnhandled;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ID of the last linked item.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public int LastLinkedItemId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the flags of the last linked item.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public byte LastLinkedItemFlags { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -139,76 +89,36 @@ public sealed class ChatGui : IDisposable, IServiceType
|
|||
this.interactableLinkClickedHook.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a chat message. While method is named as PrintChat, it only add a entry to the queue,
|
||||
/// later to be processed when UpdateQueue() is called.
|
||||
/// </summary>
|
||||
/// <param name="chat">A message to send.</param>
|
||||
public void PrintChat(XivChatEntry chat)
|
||||
/// <inheritdoc/>
|
||||
public void Print(XivChatEntry chat)
|
||||
{
|
||||
this.chatQueue.Enqueue(chat);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a chat message. While method is named as PrintChat (it calls it internally), it only add a entry to the queue,
|
||||
/// later to be processed when UpdateQueue() is called.
|
||||
/// </summary>
|
||||
/// <param name="message">A message to send.</param>
|
||||
public void Print(string message)
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Print(string message, string? messageTag = null, ushort? tagColor = null)
|
||||
{
|
||||
// Log.Verbose("[CHATGUI PRINT REGULAR]{0}", message);
|
||||
this.PrintChat(new XivChatEntry
|
||||
{
|
||||
Message = message,
|
||||
Type = this.configuration.GeneralChatType,
|
||||
});
|
||||
this.PrintTagged(message, this.configuration.GeneralChatType, messageTag, tagColor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a chat message. While method is named as PrintChat (it calls it internally), it only add a entry to the queue,
|
||||
/// later to be processed when UpdateQueue() is called.
|
||||
/// </summary>
|
||||
/// <param name="message">A message to send.</param>
|
||||
public void Print(SeString message)
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Print(SeString message, string? messageTag = null, ushort? tagColor = null)
|
||||
{
|
||||
// Log.Verbose("[CHATGUI PRINT SESTRING]{0}", message.TextValue);
|
||||
this.PrintChat(new XivChatEntry
|
||||
{
|
||||
Message = message,
|
||||
Type = this.configuration.GeneralChatType,
|
||||
});
|
||||
this.PrintTagged(message, this.configuration.GeneralChatType, messageTag, tagColor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue an error chat message. While method is named as PrintChat (it calls it internally), it only add a entry to
|
||||
/// the queue, later to be processed when UpdateQueue() is called.
|
||||
/// </summary>
|
||||
/// <param name="message">A message to send.</param>
|
||||
public void PrintError(string message)
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void PrintError(string message, string? messageTag = null, ushort? tagColor = null)
|
||||
{
|
||||
// Log.Verbose("[CHATGUI PRINT REGULAR ERROR]{0}", message);
|
||||
this.PrintChat(new XivChatEntry
|
||||
{
|
||||
Message = message,
|
||||
Type = XivChatType.Urgent,
|
||||
});
|
||||
this.PrintTagged(message, XivChatType.Urgent, messageTag, tagColor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue an error chat message. While method is named as PrintChat (it calls it internally), it only add a entry to
|
||||
/// the queue, later to be processed when UpdateQueue() is called.
|
||||
/// </summary>
|
||||
/// <param name="message">A message to send.</param>
|
||||
public void PrintError(SeString message)
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void PrintError(SeString message, string? messageTag = null, ushort? tagColor = null)
|
||||
{
|
||||
// Log.Verbose("[CHATGUI PRINT SESTRING ERROR]{0}", message.TextValue);
|
||||
this.PrintChat(new XivChatEntry
|
||||
{
|
||||
Message = message,
|
||||
Type = XivChatType.Urgent,
|
||||
});
|
||||
this.PrintTagged(message, XivChatType.Urgent, messageTag, tagColor);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Process a chat queue.
|
||||
/// </summary>
|
||||
|
|
@ -242,7 +152,7 @@ public sealed class ChatGui : IDisposable, IServiceType
|
|||
/// <returns>A payload for handling.</returns>
|
||||
internal DalamudLinkPayload AddChatLinkHandler(string pluginName, uint commandId, Action<uint, SeString> commandAction)
|
||||
{
|
||||
var payload = new DalamudLinkPayload() { Plugin = pluginName, CommandId = commandId };
|
||||
var payload = new DalamudLinkPayload { Plugin = pluginName, CommandId = commandId };
|
||||
this.dalamudLinkHandlers.Add((pluginName, commandId), commandAction);
|
||||
return payload;
|
||||
}
|
||||
|
|
@ -266,20 +176,63 @@ public sealed class ChatGui : IDisposable, IServiceType
|
|||
/// <param name="commandId">The ID of the command to be removed.</param>
|
||||
internal void RemoveChatLinkHandler(string pluginName, uint commandId)
|
||||
{
|
||||
if (this.dalamudLinkHandlers.ContainsKey((pluginName, commandId)))
|
||||
{
|
||||
this.dalamudLinkHandlers.Remove((pluginName, commandId));
|
||||
}
|
||||
this.dalamudLinkHandlers.Remove((pluginName, commandId));
|
||||
}
|
||||
|
||||
[ServiceManager.CallWhenServicesReady]
|
||||
private void ContinueConstruction(GameGui gameGui, LibcFunction libcFunction)
|
||||
private void ContinueConstruction()
|
||||
{
|
||||
this.printMessageHook.Enable();
|
||||
this.populateItemLinkHook.Enable();
|
||||
this.interactableLinkClickedHook.Enable();
|
||||
}
|
||||
|
||||
private void PrintTagged(string message, XivChatType channel, string? tag, ushort? color)
|
||||
{
|
||||
var builder = new SeStringBuilder();
|
||||
|
||||
if (!tag.IsNullOrEmpty())
|
||||
{
|
||||
if (color is not null)
|
||||
{
|
||||
builder.AddUiForeground($"[{tag}] ", color.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AddText($"[{tag}] ");
|
||||
}
|
||||
}
|
||||
|
||||
this.Print(new XivChatEntry
|
||||
{
|
||||
Message = builder.AddText(message).Build(),
|
||||
Type = channel,
|
||||
});
|
||||
}
|
||||
|
||||
private void PrintTagged(SeString message, XivChatType channel, string? tag, ushort? color)
|
||||
{
|
||||
var builder = new SeStringBuilder();
|
||||
|
||||
if (!tag.IsNullOrEmpty())
|
||||
{
|
||||
if (color is not null)
|
||||
{
|
||||
builder.AddUiForeground($"[{tag}] ", color.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AddText($"[{tag}] ");
|
||||
}
|
||||
}
|
||||
|
||||
this.Print(new XivChatEntry
|
||||
{
|
||||
Message = builder.Build().Append(message),
|
||||
Type = channel,
|
||||
});
|
||||
}
|
||||
|
||||
private void HandlePopulateItemLinkDetour(IntPtr linkObjectPtr, IntPtr itemInfoPtr)
|
||||
{
|
||||
try
|
||||
|
|
@ -298,7 +251,7 @@ public sealed class ChatGui : IDisposable, IServiceType
|
|||
}
|
||||
}
|
||||
|
||||
private IntPtr HandlePrintMessageDetour(IntPtr manager, XivChatType chattype, IntPtr pSenderName, IntPtr pMessage, uint senderid, IntPtr parameter)
|
||||
private IntPtr HandlePrintMessageDetour(IntPtr manager, XivChatType chatType, IntPtr pSenderName, IntPtr pMessage, uint senderId, IntPtr parameter)
|
||||
{
|
||||
var retVal = IntPtr.Zero;
|
||||
|
||||
|
|
@ -325,13 +278,13 @@ public sealed class ChatGui : IDisposable, IServiceType
|
|||
// Call events
|
||||
var isHandled = false;
|
||||
|
||||
var invocationList = this.CheckMessageHandled.GetInvocationList();
|
||||
var invocationList = this.CheckMessageHandled!.GetInvocationList();
|
||||
foreach (var @delegate in invocationList)
|
||||
{
|
||||
try
|
||||
{
|
||||
var messageHandledDelegate = @delegate as OnCheckMessageHandledDelegate;
|
||||
messageHandledDelegate!.Invoke(chattype, senderid, ref parsedSender, ref parsedMessage, ref isHandled);
|
||||
var messageHandledDelegate = @delegate as IChatGui.OnCheckMessageHandledDelegate;
|
||||
messageHandledDelegate!.Invoke(chatType, senderId, ref parsedSender, ref parsedMessage, ref isHandled);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
@ -341,13 +294,13 @@ public sealed class ChatGui : IDisposable, IServiceType
|
|||
|
||||
if (!isHandled)
|
||||
{
|
||||
invocationList = this.ChatMessage.GetInvocationList();
|
||||
invocationList = this.ChatMessage!.GetInvocationList();
|
||||
foreach (var @delegate in invocationList)
|
||||
{
|
||||
try
|
||||
{
|
||||
var messageHandledDelegate = @delegate as OnMessageDelegate;
|
||||
messageHandledDelegate!.Invoke(chattype, senderid, ref parsedSender, ref parsedMessage, ref isHandled);
|
||||
var messageHandledDelegate = @delegate as IChatGui.OnMessageDelegate;
|
||||
messageHandledDelegate!.Invoke(chatType, senderId, ref parsedSender, ref parsedMessage, ref isHandled);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
@ -390,12 +343,12 @@ public sealed class ChatGui : IDisposable, IServiceType
|
|||
// Print the original chat if it's handled.
|
||||
if (isHandled)
|
||||
{
|
||||
this.ChatMessageHandled?.Invoke(chattype, senderid, parsedSender, parsedMessage);
|
||||
this.ChatMessageHandled?.Invoke(chatType, senderId, parsedSender, parsedMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = this.printMessageHook.Original(manager, chattype, senderPtr, messagePtr, senderid, parameter);
|
||||
this.ChatMessageUnhandled?.Invoke(chattype, senderid, parsedSender, parsedMessage);
|
||||
retVal = this.printMessageHook.Original(manager, chatType, senderPtr, messagePtr, senderId, parameter);
|
||||
this.ChatMessageUnhandled?.Invoke(chatType, senderId, parsedSender, parsedMessage);
|
||||
}
|
||||
|
||||
if (this.baseAddress == IntPtr.Zero)
|
||||
|
|
@ -407,7 +360,7 @@ public sealed class ChatGui : IDisposable, IServiceType
|
|||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Exception on OnChatMessage hook.");
|
||||
retVal = this.printMessageHook.Original(manager, chattype, pSenderName, pMessage, senderid, parameter);
|
||||
retVal = this.printMessageHook.Original(manager, chatType, pSenderName, pMessage, senderId, parameter);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
|
@ -439,10 +392,10 @@ public sealed class ChatGui : IDisposable, IServiceType
|
|||
var linkPayload = payloads[0];
|
||||
if (linkPayload is DalamudLinkPayload link)
|
||||
{
|
||||
if (this.dalamudLinkHandlers.ContainsKey((link.Plugin, link.CommandId)))
|
||||
if (this.dalamudLinkHandlers.TryGetValue((link.Plugin, link.CommandId), out var value))
|
||||
{
|
||||
Log.Verbose($"Sending DalamudLink to {link.Plugin}: {link.CommandId}");
|
||||
this.dalamudLinkHandlers[(link.Plugin, link.CommandId)].Invoke(link.CommandId, new SeString(payloads));
|
||||
value.Invoke(link.CommandId, new SeString(payloads));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -456,3 +409,93 @@ public sealed class ChatGui : IDisposable, IServiceType
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plugin scoped version of ChatGui.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.ScopedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IChatGui>]
|
||||
#pragma warning restore SA1015
|
||||
internal class ChatGuiPluginScoped : IDisposable, IServiceType, IChatGui
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly ChatGui chatGuiService = Service<ChatGui>.Get();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ChatGuiPluginScoped"/> class.
|
||||
/// </summary>
|
||||
internal ChatGuiPluginScoped()
|
||||
{
|
||||
this.chatGuiService.ChatMessage += this.OnMessageForward;
|
||||
this.chatGuiService.CheckMessageHandled += this.OnCheckMessageForward;
|
||||
this.chatGuiService.ChatMessageHandled += this.OnMessageHandledForward;
|
||||
this.chatGuiService.ChatMessageUnhandled += this.OnMessageUnhandledForward;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IChatGui.OnMessageDelegate? ChatMessage;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IChatGui.OnCheckMessageHandledDelegate? CheckMessageHandled;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IChatGui.OnMessageHandledDelegate? ChatMessageHandled;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IChatGui.OnMessageUnhandledDelegate? ChatMessageUnhandled;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int LastLinkedItemId => this.chatGuiService.LastLinkedItemId;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public byte LastLinkedItemFlags => this.chatGuiService.LastLinkedItemFlags;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.chatGuiService.ChatMessage -= this.OnMessageForward;
|
||||
this.chatGuiService.CheckMessageHandled -= this.OnCheckMessageForward;
|
||||
this.chatGuiService.ChatMessageHandled -= this.OnMessageHandledForward;
|
||||
this.chatGuiService.ChatMessageUnhandled -= this.OnMessageUnhandledForward;
|
||||
|
||||
this.ChatMessage = null;
|
||||
this.CheckMessageHandled = null;
|
||||
this.ChatMessageHandled = null;
|
||||
this.ChatMessageUnhandled = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Print(XivChatEntry chat)
|
||||
=> this.chatGuiService.Print(chat);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Print(string message, string? messageTag = null, ushort? tagColor = null)
|
||||
=> this.chatGuiService.Print(message, messageTag, tagColor);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Print(SeString message, string? messageTag = null, ushort? tagColor = null)
|
||||
=> this.chatGuiService.Print(message, messageTag, tagColor);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void PrintError(string message, string? messageTag = null, ushort? tagColor = null)
|
||||
=> this.chatGuiService.PrintError(message, messageTag, tagColor);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void PrintError(SeString message, string? messageTag = null, ushort? tagColor = null)
|
||||
=> this.chatGuiService.PrintError(message, messageTag, tagColor);
|
||||
|
||||
private void OnMessageForward(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled)
|
||||
=> this.ChatMessage?.Invoke(type, senderId, ref sender, ref message, ref isHandled);
|
||||
|
||||
private void OnCheckMessageForward(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled)
|
||||
=> this.CheckMessageHandled?.Invoke(type, senderId, ref sender, ref message, ref isHandled);
|
||||
|
||||
private void OnMessageHandledForward(XivChatType type, uint senderId, SeString sender, SeString message)
|
||||
=> this.ChatMessageHandled?.Invoke(type, senderId, sender, message);
|
||||
|
||||
private void OnMessageUnhandledForward(XivChatType type, uint senderId, SeString sender, SeString message)
|
||||
=> this.ChatMessageUnhandled?.Invoke(type, senderId, sender, message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.Game.Gui;
|
||||
|
||||
/// <summary>
|
||||
/// The address resolver for the <see cref="ChatGui"/> class.
|
||||
/// </summary>
|
||||
public sealed class ChatGuiAddressResolver : BaseAddressResolver
|
||||
internal sealed class ChatGuiAddressResolver : BaseAddressResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the address of the native PrintMessage method.
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Dalamud.Configuration.Internal;
|
||||
using Dalamud.Game.Addon;
|
||||
using Dalamud.Game.Addon.Events;
|
||||
using Dalamud.Game.Addon.Lifecycle;
|
||||
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
|
|
@ -19,10 +21,9 @@ namespace Dalamud.Game.Gui.Dtr;
|
|||
/// <summary>
|
||||
/// Class used to interface with the server info bar.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
public sealed unsafe class DtrBar : IDisposable, IServiceType, IDtrBar
|
||||
internal sealed unsafe class DtrBar : IDisposable, IServiceType, IDtrBar
|
||||
{
|
||||
private const uint BaseNodeId = 1000;
|
||||
|
||||
|
|
@ -165,7 +166,7 @@ public sealed unsafe class DtrBar : IDisposable, IServiceType, IDtrBar
|
|||
|
||||
private AtkUnitBase* GetDtr() => (AtkUnitBase*)this.gameGui.GetAddonByName("_DTR").ToPointer();
|
||||
|
||||
private void Update(Framework unused)
|
||||
private void Update(IFramework unused)
|
||||
{
|
||||
this.HandleRemovedNodes();
|
||||
this.HandleAddedNodes();
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using Dalamud.Hooking;
|
|||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Memory;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Game.Gui.FlyText;
|
||||
|
|
@ -14,10 +15,9 @@ namespace Dalamud.Game.Gui.FlyText;
|
|||
/// <summary>
|
||||
/// This class facilitates interacting with and creating native in-game "fly text".
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
public sealed class FlyTextGui : IDisposable, IServiceType
|
||||
internal sealed class FlyTextGui : IDisposable, IServiceType, IFlyTextGui
|
||||
{
|
||||
/// <summary>
|
||||
/// The native function responsible for adding fly text to the UI. See <see cref="FlyTextGuiAddressResolver.AddFlyText"/>.
|
||||
|
|
@ -30,7 +30,7 @@ public sealed class FlyTextGui : IDisposable, IServiceType
|
|||
private readonly Hook<CreateFlyTextDelegate> createFlyTextHook;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private FlyTextGui(SigScanner sigScanner)
|
||||
private FlyTextGui(TargetSigScanner sigScanner)
|
||||
{
|
||||
this.Address = new FlyTextGuiAddressResolver();
|
||||
this.Address.Setup(sigScanner);
|
||||
|
|
@ -39,32 +39,6 @@ public sealed class FlyTextGui : IDisposable, IServiceType
|
|||
this.createFlyTextHook = Hook<CreateFlyTextDelegate>.FromAddress(this.Address.CreateFlyText, this.CreateFlyTextDetour);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The delegate defining the type for the FlyText event.
|
||||
/// </summary>
|
||||
/// <param name="kind">The FlyTextKind. See <see cref="FlyTextKind"/>.</param>
|
||||
/// <param name="val1">Value1 passed to the native flytext function.</param>
|
||||
/// <param name="val2">Value2 passed to the native flytext function. Seems unused.</param>
|
||||
/// <param name="text1">Text1 passed to the native flytext function.</param>
|
||||
/// <param name="text2">Text2 passed to the native flytext function.</param>
|
||||
/// <param name="color">Color passed to the native flytext function. Changes flytext color.</param>
|
||||
/// <param name="icon">Icon ID passed to the native flytext function. Only displays with select FlyTextKind.</param>
|
||||
/// <param name="damageTypeIcon">Damage Type Icon ID passed to the native flytext function. Displayed next to damage values to denote damage type.</param>
|
||||
/// <param name="yOffset">The vertical offset to place the flytext at. 0 is default. Negative values result
|
||||
/// in text appearing higher on the screen. This does not change where the element begins to fade.</param>
|
||||
/// <param name="handled">Whether this flytext has been handled. If a subscriber sets this to true, the FlyText will not appear.</param>
|
||||
public delegate void OnFlyTextCreatedDelegate(
|
||||
ref FlyTextKind kind,
|
||||
ref int val1,
|
||||
ref int val2,
|
||||
ref SeString text1,
|
||||
ref SeString text2,
|
||||
ref uint color,
|
||||
ref uint icon,
|
||||
ref uint damageTypeIcon,
|
||||
ref float yOffset,
|
||||
ref bool handled);
|
||||
|
||||
/// <summary>
|
||||
/// Private delegate for the native CreateFlyText function's hook.
|
||||
/// </summary>
|
||||
|
|
@ -95,12 +69,8 @@ public sealed class FlyTextGui : IDisposable, IServiceType
|
|||
uint offsetStrMax,
|
||||
int unknown);
|
||||
|
||||
/// <summary>
|
||||
/// The FlyText event that can be subscribed to.
|
||||
/// </summary>
|
||||
public event OnFlyTextCreatedDelegate? FlyTextCreated;
|
||||
|
||||
private Dalamud Dalamud { get; }
|
||||
/// <inheritdoc/>
|
||||
public event IFlyTextGui.OnFlyTextCreatedDelegate? FlyTextCreated;
|
||||
|
||||
private FlyTextGuiAddressResolver Address { get; }
|
||||
|
||||
|
|
@ -112,18 +82,7 @@ public sealed class FlyTextGui : IDisposable, IServiceType
|
|||
this.createFlyTextHook.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays a fly text in-game on the local player.
|
||||
/// </summary>
|
||||
/// <param name="kind">The FlyTextKind. See <see cref="FlyTextKind"/>.</param>
|
||||
/// <param name="actorIndex">The index of the actor to place flytext on. Indexing unknown. 1 places flytext on local player.</param>
|
||||
/// <param name="val1">Value1 passed to the native flytext function.</param>
|
||||
/// <param name="val2">Value2 passed to the native flytext function. Seems unused.</param>
|
||||
/// <param name="text1">Text1 passed to the native flytext function.</param>
|
||||
/// <param name="text2">Text2 passed to the native flytext function.</param>
|
||||
/// <param name="color">Color passed to the native flytext function. Changes flytext color.</param>
|
||||
/// <param name="icon">Icon ID passed to the native flytext function. Only displays with select FlyTextKind.</param>
|
||||
/// <param name="damageTypeIcon">Damage Type Icon ID passed to the native flytext function. Displayed next to damage values to denote damage type.</param>
|
||||
/// <inheritdoc/>
|
||||
public unsafe void AddFlyText(FlyTextKind kind, uint actorIndex, uint val1, uint val2, SeString text1, SeString text2, uint color, uint icon, uint damageTypeIcon)
|
||||
{
|
||||
// Known valid flytext region within the atk arrays
|
||||
|
|
@ -318,3 +277,46 @@ public sealed class FlyTextGui : IDisposable, IServiceType
|
|||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plugin scoped version of FlyTextGui.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.ScopedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IFlyTextGui>]
|
||||
#pragma warning restore SA1015
|
||||
internal class FlyTextGuiPluginScoped : IDisposable, IServiceType, IFlyTextGui
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly FlyTextGui flyTextGuiService = Service<FlyTextGui>.Get();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FlyTextGuiPluginScoped"/> class.
|
||||
/// </summary>
|
||||
internal FlyTextGuiPluginScoped()
|
||||
{
|
||||
this.flyTextGuiService.FlyTextCreated += this.FlyTextCreatedForward;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IFlyTextGui.OnFlyTextCreatedDelegate? FlyTextCreated;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.flyTextGuiService.FlyTextCreated -= this.FlyTextCreatedForward;
|
||||
|
||||
this.FlyTextCreated = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void AddFlyText(FlyTextKind kind, uint actorIndex, uint val1, uint val2, SeString text1, SeString text2, uint color, uint icon, uint damageTypeIcon)
|
||||
{
|
||||
this.flyTextGuiService.AddFlyText(kind, actorIndex, val1, val2, text1, text2, color, icon, damageTypeIcon);
|
||||
}
|
||||
|
||||
private void FlyTextCreatedForward(ref FlyTextKind kind, ref int val1, ref int val2, ref SeString text1, ref SeString text2, ref uint color, ref uint icon, ref uint damageTypeIcon, ref float yOffset, ref bool handled)
|
||||
=> this.FlyTextCreated?.Invoke(ref kind, ref val1, ref val2, ref text1, ref text2, ref color, ref icon, ref damageTypeIcon, ref yOffset, ref handled);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.Game.Gui.FlyText;
|
||||
|
||||
/// <summary>
|
||||
/// An address resolver for the <see cref="FlyTextGui"/> class.
|
||||
/// </summary>
|
||||
public class FlyTextGuiAddressResolver : BaseAddressResolver
|
||||
internal class FlyTextGuiAddressResolver : BaseAddressResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the address of the native AddFlyText method, which occurs
|
||||
|
|
|
|||
|
|
@ -1,57 +1,58 @@
|
|||
namespace Dalamud.Game.Gui.FlyText;
|
||||
|
||||
/// <summary>
|
||||
/// Enum of FlyTextKind values. Members suffixed with
|
||||
/// a number seem to be a duplicate, or perform duplicate behavior.
|
||||
/// Enum of FlyTextKind values.
|
||||
/// </summary>
|
||||
public enum FlyTextKind : int
|
||||
{
|
||||
/// <summary>
|
||||
/// Val1 in serif font, Text2 in sans-serif as subtitle.
|
||||
/// Used for autos and incoming DoTs.
|
||||
/// </summary>
|
||||
AutoAttack = 0,
|
||||
AutoAttackOrDot = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in serif font, Text2 in sans-serif as subtitle.
|
||||
/// Does a bounce effect on appearance.
|
||||
/// </summary>
|
||||
DirectHit = 1,
|
||||
AutoAttackOrDotDh = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in larger serif font with exclamation, with Text2 in sans-serif as subtitle.
|
||||
/// Does a bigger bounce effect on appearance.
|
||||
/// </summary>
|
||||
CriticalHit = 2,
|
||||
AutoAttackOrDotCrit = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in even larger serif font with 2 exclamations, Text2 in
|
||||
/// sans-serif as subtitle. Does a large bounce effect on appearance.
|
||||
/// Does not scroll up or down the screen.
|
||||
/// Val1 in even larger serif font with 2 exclamations, Text2 in sans-serif as subtitle.
|
||||
/// Does a large bounce effect on appearance. Does not scroll up or down the screen.
|
||||
/// </summary>
|
||||
CriticalDirectHit = 3,
|
||||
AutoAttackOrDotCritDh = 3,
|
||||
|
||||
/// <summary>
|
||||
/// AutoAttack with sans-serif Text1 to the left of the Val1.
|
||||
/// Val1 in serif font, Text2 in sans-serif as subtitle with sans-serif Text1 to the left of the Val1.
|
||||
/// </summary>
|
||||
NamedAttack = 4,
|
||||
Damage = 4,
|
||||
|
||||
/// <summary>
|
||||
/// DirectHit with sans-serif Text1 to the left of the Val1.
|
||||
/// Val1 in serif font, Text2 in sans-serif as subtitle with sans-serif Text1 to the left of the Val1.
|
||||
/// Does a bounce effect on appearance.
|
||||
/// </summary>
|
||||
NamedDirectHit = 5,
|
||||
DamageDh = 5,
|
||||
|
||||
/// <summary>
|
||||
/// CriticalHit with sans-serif Text1 to the left of the Val1.
|
||||
/// Val1 in larger serif font with exclamation, with Text2 in sans-serif as subtitle with sans-serif Text1 to the left of the Val1.
|
||||
/// Does a bigger bounce effect on appearance.
|
||||
/// </summary>
|
||||
NamedCriticalHit = 6,
|
||||
DamageCrit = 6,
|
||||
|
||||
/// <summary>
|
||||
/// CriticalDirectHit with sans-serif Text1 to the left of the Val1.
|
||||
/// Val1 in even larger serif font with 2 exclamations, Text2 in sans-serif as subtitle with sans-serif Text1 to the left of the Val1.
|
||||
/// Does a large bounce effect on appearance. Does not scroll up or down the screen.
|
||||
/// </summary>
|
||||
NamedCriticalDirectHit = 7,
|
||||
DamageCritDh = 7,
|
||||
|
||||
/// <summary>
|
||||
/// The text changes to DODGE under certain circumstances.
|
||||
/// All caps, serif MISS.
|
||||
/// </summary>
|
||||
Miss = 8,
|
||||
|
|
@ -74,12 +75,12 @@ public enum FlyTextKind : int
|
|||
/// <summary>
|
||||
/// Icon next to sans-serif Text1.
|
||||
/// </summary>
|
||||
NamedIcon = 12,
|
||||
Buff = 12,
|
||||
|
||||
/// <summary>
|
||||
/// Icon next to sans-serif Text1 (2).
|
||||
/// Icon next to sans-serif Text1.
|
||||
/// </summary>
|
||||
NamedIcon2 = 13,
|
||||
Debuff = 13,
|
||||
|
||||
/// <summary>
|
||||
/// Serif Val1 with all caps condensed font EXP with Text2 in sans-serif as subtitle.
|
||||
|
|
@ -94,42 +95,44 @@ public enum FlyTextKind : int
|
|||
/// <summary>
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font MP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
NamedMp = 16,
|
||||
MpDrain = 16,
|
||||
|
||||
/// <summary>
|
||||
/// Currently not used by the game.
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font TP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
NamedTp = 17,
|
||||
|
||||
/// <summary>
|
||||
/// AutoAttack with sans-serif Text1 to the left of the Val1 (2).
|
||||
/// Val1 in serif font, Text2 in sans-serif as subtitle with sans-serif Text1 to the left of the Val1.
|
||||
/// </summary>
|
||||
NamedAttack2 = 18,
|
||||
Healing = 18,
|
||||
|
||||
/// <summary>
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font MP with Text2 in sans-serif as subtitle (2).
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font MP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
NamedMp2 = 19,
|
||||
MpRegen = 19,
|
||||
|
||||
/// <summary>
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font TP with Text2 in sans-serif as subtitle (2).
|
||||
/// Currently not used by the game.
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font TP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
NamedTp2 = 20,
|
||||
|
||||
/// <summary>
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font EP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
NamedEp = 21,
|
||||
EpRegen = 21,
|
||||
|
||||
/// <summary>
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font CP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
NamedCp = 22,
|
||||
CpRegen = 22,
|
||||
|
||||
/// <summary>
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font GP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
NamedGp = 23,
|
||||
GpRegen = 23,
|
||||
|
||||
/// <summary>
|
||||
/// Displays nothing.
|
||||
|
|
@ -149,57 +152,59 @@ public enum FlyTextKind : int
|
|||
Interrupted = 26,
|
||||
|
||||
/// <summary>
|
||||
/// AutoAttack with no Text2.
|
||||
/// Val1 in serif font.
|
||||
/// </summary>
|
||||
AutoAttackNoText = 27,
|
||||
CraftingProgress = 27,
|
||||
|
||||
/// <summary>
|
||||
/// AutoAttack with no Text2 (2).
|
||||
/// Val1 in serif font.
|
||||
/// </summary>
|
||||
AutoAttackNoText2 = 28,
|
||||
CraftingQuality = 28,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in larger serif font with exclamation, with Text2 in sans-serif as subtitle. Does a bigger bounce effect on appearance (2).
|
||||
/// Val1 in larger serif font with exclamation, with Text2 in sans-serif as subtitle. Does a bigger bounce effect on appearance.
|
||||
/// </summary>
|
||||
CriticalHit2 = 29,
|
||||
CraftingQualityCrit = 29,
|
||||
|
||||
/// <summary>
|
||||
/// AutoAttack with no Text2 (3).
|
||||
/// Currently not used by the game.
|
||||
/// Val1 in serif font.
|
||||
/// </summary>
|
||||
AutoAttackNoText3 = 30,
|
||||
|
||||
/// <summary>
|
||||
/// CriticalHit with sans-serif Text1 to the left of the Val1 (2).
|
||||
/// </summary>
|
||||
NamedCriticalHit2 = 31,
|
||||
HealingCrit = 31,
|
||||
|
||||
/// <summary>
|
||||
/// Same as NamedCriticalHit with a green (cannot change) MP in condensed font to the right of Val1.
|
||||
/// Currently not used by the game.
|
||||
/// Same as DamageCrit with a MP in condensed font to the right of Val1.
|
||||
/// Does a jiggle effect to the right on appearance.
|
||||
/// </summary>
|
||||
NamedCriticalHitWithMp = 32,
|
||||
|
||||
/// <summary>
|
||||
/// Same as NamedCriticalHit with a yellow (cannot change) TP in condensed font to the right of Val1.
|
||||
/// Currently not used by the game.
|
||||
/// Same as DamageCrit with a TP in condensed font to the right of Val1.
|
||||
/// Does a jiggle effect to the right on appearance.
|
||||
/// </summary>
|
||||
NamedCriticalHitWithTp = 33,
|
||||
|
||||
/// <summary>
|
||||
/// Same as NamedIcon with sans-serif "has no effect!" to the right.
|
||||
/// Icon next to sans-serif Text1 with sans-serif "has no effect!" to the right.
|
||||
/// </summary>
|
||||
NamedIconHasNoEffect = 34,
|
||||
DebuffNoEffect = 34,
|
||||
|
||||
/// <summary>
|
||||
/// Same as NamedIcon but Text1 is slightly faded. Used for buff expiration.
|
||||
/// Icon next to sans-serif slightly faded Text1.
|
||||
/// </summary>
|
||||
NamedIconFaded = 35,
|
||||
BuffFading = 35,
|
||||
|
||||
/// <summary>
|
||||
/// Same as NamedIcon but Text1 is slightly faded (2).
|
||||
/// Used for buff expiration.
|
||||
/// Icon next to sans-serif slightly faded Text1.
|
||||
/// </summary>
|
||||
NamedIconFaded2 = 36,
|
||||
DebuffFading = 36,
|
||||
|
||||
/// <summary>
|
||||
/// Text1 in sans-serif font.
|
||||
|
|
@ -207,9 +212,9 @@ public enum FlyTextKind : int
|
|||
Named = 37,
|
||||
|
||||
/// <summary>
|
||||
/// Same as NamedIcon with sans-serif "(fully resisted)" to the right.
|
||||
/// Icon next to sans-serif Text1 with sans-serif "(fully resisted)" to the right.
|
||||
/// </summary>
|
||||
NamedIconFullyResisted = 38,
|
||||
DebuffResisted = 38,
|
||||
|
||||
/// <summary>
|
||||
/// All caps serif 'INCAPACITATED!'.
|
||||
|
|
@ -219,32 +224,34 @@ public enum FlyTextKind : int
|
|||
/// <summary>
|
||||
/// Text1 with sans-serif "(fully resisted)" to the right.
|
||||
/// </summary>
|
||||
NamedFullyResisted = 40,
|
||||
FullyResisted = 40,
|
||||
|
||||
/// <summary>
|
||||
/// Text1 with sans-serif "has no effect!" to the right.
|
||||
/// </summary>
|
||||
NamedHasNoEffect = 41,
|
||||
HasNoEffect = 41,
|
||||
|
||||
/// <summary>
|
||||
/// AutoAttack with sans-serif Text1 to the left of the Val1 (3).
|
||||
/// Val1 in serif font, Text2 in sans-serif as subtitle with sans-serif Text1 to the left of the Val1.
|
||||
/// </summary>
|
||||
NamedAttack3 = 42,
|
||||
HpDrain = 42,
|
||||
|
||||
/// <summary>
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font MP with Text2 in sans-serif as subtitle (3).
|
||||
/// Currently not used by the game.
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font MP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
NamedMp3 = 43,
|
||||
|
||||
/// <summary>
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font TP with Text2 in sans-serif as subtitle (3).
|
||||
/// Currently not used by the game.
|
||||
/// Sans-serif Text1 next to serif Val1 with all caps condensed font TP with Text2 in sans-serif as subtitle.
|
||||
/// </summary>
|
||||
NamedTp3 = 44,
|
||||
|
||||
/// <summary>
|
||||
/// Same as NamedIcon with serif "INVULNERABLE!" beneath the Text1.
|
||||
/// Icon next to sans-serif Text1 with serif "INVULNERABLE!" beneath the Text1.
|
||||
/// </summary>
|
||||
NamedIconInvulnerable = 45,
|
||||
DebuffInvulnerable = 45,
|
||||
|
||||
/// <summary>
|
||||
/// All caps serif RESIST.
|
||||
|
|
@ -252,20 +259,20 @@ public enum FlyTextKind : int
|
|||
Resist = 46,
|
||||
|
||||
/// <summary>
|
||||
/// Same as NamedIcon but places the given icon in the item icon outline.
|
||||
/// Icon with an item icon outline next to sans-serif Text1.
|
||||
/// </summary>
|
||||
NamedIconWithItemOutline = 47,
|
||||
LootedItem = 47,
|
||||
|
||||
/// <summary>
|
||||
/// AutoAttack with no Text2 (4).
|
||||
/// Val1 in serif font.
|
||||
/// </summary>
|
||||
AutoAttackNoText4 = 48,
|
||||
Collectability = 48,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in larger serif font with exclamation, with Text2 in sans-serif as subtitle (3).
|
||||
/// Val1 in larger serif font with exclamation, with Text2 in sans-serif as subtitle.
|
||||
/// Does a bigger bounce effect on appearance.
|
||||
/// </summary>
|
||||
CriticalHit3 = 49,
|
||||
CollectabilityCrit = 49,
|
||||
|
||||
/// <summary>
|
||||
/// All caps serif REFLECT.
|
||||
|
|
@ -278,20 +285,21 @@ public enum FlyTextKind : int
|
|||
Reflected = 51,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in serif font, Text2 in sans-serif as subtitle (2).
|
||||
/// Val1 in serif font, Text2 in sans-serif as subtitle.
|
||||
/// Does a bounce effect on appearance.
|
||||
/// </summary>
|
||||
DirectHit2 = 52,
|
||||
CraftingQualityDh = 52,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in larger serif font with exclamation, with Text2 in sans-serif as subtitle (4).
|
||||
/// Currently not used by the game.
|
||||
/// Val1 in larger serif font with exclamation, with Text2 in sans-serif as subtitle.
|
||||
/// Does a bigger bounce effect on appearance.
|
||||
/// </summary>
|
||||
CriticalHit4 = 53,
|
||||
|
||||
/// <summary>
|
||||
/// Val1 in even larger serif font with 2 exclamations, Text2 in sans-serif as subtitle (2).
|
||||
/// Val1 in even larger serif font with 2 exclamations, Text2 in sans-serif as subtitle.
|
||||
/// Does a large bounce effect on appearance. Does not scroll up or down the screen.
|
||||
/// </summary>
|
||||
CriticalDirectHit2 = 54,
|
||||
CraftingQualityCritDh = 54,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Logging.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
|
|
@ -15,7 +15,6 @@ using FFXIVClientStructs.FFXIV.Client.UI;
|
|||
using FFXIVClientStructs.FFXIV.Common.Component.BGCollision;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using ImGuiNET;
|
||||
using Serilog;
|
||||
using SharpDX;
|
||||
|
||||
using Vector2 = System.Numerics.Vector2;
|
||||
|
|
@ -26,14 +25,12 @@ namespace Dalamud.Game.Gui;
|
|||
/// <summary>
|
||||
/// A class handling many aspects of the in-game UI.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IGameGui>]
|
||||
#pragma warning restore SA1015
|
||||
public sealed unsafe class GameGui : IDisposable, IServiceType, IGameGui
|
||||
internal sealed unsafe class GameGui : IDisposable, IServiceType, IGameGui
|
||||
{
|
||||
private static readonly ModuleLog Log = new("GameGui");
|
||||
|
||||
private readonly GameGuiAddressResolver address;
|
||||
|
||||
private readonly GetMatrixSingletonDelegate getMatrixSingleton;
|
||||
|
|
@ -47,11 +44,11 @@ public sealed unsafe class GameGui : IDisposable, IServiceType, IGameGui
|
|||
private readonly Hook<ToggleUiHideDelegate> toggleUiHideHook;
|
||||
private readonly Hook<Utf8StringFromSequenceDelegate> utf8StringFromSequenceHook;
|
||||
|
||||
private GetUIMapObjectDelegate getUIMapObject;
|
||||
private OpenMapWithFlagDelegate openMapWithFlag;
|
||||
private GetUIMapObjectDelegate? getUIMapObject;
|
||||
private OpenMapWithFlagDelegate? openMapWithFlag;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private GameGui(SigScanner sigScanner)
|
||||
private GameGui(TargetSigScanner sigScanner)
|
||||
{
|
||||
this.address = new GameGuiAddressResolver();
|
||||
this.address.Setup(sigScanner);
|
||||
|
|
@ -115,16 +112,16 @@ public sealed unsafe class GameGui : IDisposable, IServiceType, IGameGui
|
|||
private delegate char HandleImmDelegate(IntPtr framework, char a2, byte a3);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
private delegate IntPtr ToggleUiHideDelegate(IntPtr thisPtr, byte unknownByte);
|
||||
private delegate IntPtr ToggleUiHideDelegate(IntPtr thisPtr, bool uiVisible);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<bool> UiHideToggled;
|
||||
public event EventHandler<bool>? UiHideToggled;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ulong> HoveredItemChanged;
|
||||
public event EventHandler<ulong>? HoveredItemChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<HoveredAction> HoveredActionChanged;
|
||||
public event EventHandler<HoveredAction>? HoveredActionChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool GameUiHidden { get; private set; }
|
||||
|
|
@ -146,7 +143,7 @@ public sealed unsafe class GameGui : IDisposable, IServiceType, IGameGui
|
|||
return false;
|
||||
}
|
||||
|
||||
this.getUIMapObject = this.address.GetVirtualFunction<GetUIMapObjectDelegate>(uiModule, 0, 8);
|
||||
this.getUIMapObject ??= this.address.GetVirtualFunction<GetUIMapObjectDelegate>(uiModule, 0, 8);
|
||||
|
||||
var uiMapObjectPtr = this.getUIMapObject(uiModule);
|
||||
|
||||
|
|
@ -156,7 +153,7 @@ public sealed unsafe class GameGui : IDisposable, IServiceType, IGameGui
|
|||
return false;
|
||||
}
|
||||
|
||||
this.openMapWithFlag = this.address.GetVirtualFunction<OpenMapWithFlagDelegate>(uiMapObjectPtr, 0, 63);
|
||||
this.openMapWithFlag ??= this.address.GetVirtualFunction<OpenMapWithFlagDelegate>(uiMapObjectPtr, 0, 63);
|
||||
|
||||
var mapLinkString = mapLink.DataString;
|
||||
|
||||
|
|
@ -216,14 +213,13 @@ public sealed unsafe class GameGui : IDisposable, IServiceType, IGameGui
|
|||
|
||||
// Read current ViewProjectionMatrix plus game window size
|
||||
var viewProjectionMatrix = default(Matrix);
|
||||
float width, height;
|
||||
var rawMatrix = (float*)(matrixSingleton + 0x1b4).ToPointer();
|
||||
|
||||
for (var i = 0; i < 16; i++, rawMatrix++)
|
||||
viewProjectionMatrix[i] = *rawMatrix;
|
||||
|
||||
width = *rawMatrix;
|
||||
height = *(rawMatrix + 1);
|
||||
var width = *rawMatrix;
|
||||
var height = *(rawMatrix + 1);
|
||||
|
||||
viewProjectionMatrix.Invert();
|
||||
|
||||
|
|
@ -413,7 +409,7 @@ public sealed unsafe class GameGui : IDisposable, IServiceType, IGameGui
|
|||
|
||||
this.HoveredItemChanged?.InvokeSafely(this, itemId);
|
||||
|
||||
Log.Verbose("HoverItemId:{0} this:{1}", itemId, hoverState.ToInt64().ToString("X"));
|
||||
Log.Verbose($"HoverItemId:{itemId} this:{hoverState.ToInt64()}");
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
|
@ -455,7 +451,7 @@ public sealed unsafe class GameGui : IDisposable, IServiceType, IGameGui
|
|||
this.HoveredAction.ActionID = (uint)Marshal.ReadInt32(hoverState, 0x3C);
|
||||
this.HoveredActionChanged?.InvokeSafely(this, this.HoveredAction);
|
||||
|
||||
Log.Verbose("HoverActionId: {0}/{1} this:{2}", actionKind, actionId, hoverState.ToInt64().ToString("X"));
|
||||
Log.Verbose($"HoverActionId: {actionKind}/{actionId} this:{hoverState.ToInt64():X}");
|
||||
}
|
||||
|
||||
private IntPtr HandleActionOutDetour(IntPtr agentActionDetail, IntPtr a2, IntPtr a3, int a4)
|
||||
|
|
@ -488,16 +484,16 @@ public sealed unsafe class GameGui : IDisposable, IServiceType, IGameGui
|
|||
return retVal;
|
||||
}
|
||||
|
||||
private IntPtr ToggleUiHideDetour(IntPtr thisPtr, byte unknownByte)
|
||||
private IntPtr ToggleUiHideDetour(IntPtr thisPtr, bool unknownByte)
|
||||
{
|
||||
// TODO(goat): We should read this from memory directly, instead of relying on catching every toggle.
|
||||
this.GameUiHidden = !this.GameUiHidden;
|
||||
var result = this.toggleUiHideHook.Original(thisPtr, unknownByte);
|
||||
|
||||
this.GameUiHidden = !RaptureAtkModule.Instance()->IsUiVisible;
|
||||
this.UiHideToggled?.InvokeSafely(this, this.GameUiHidden);
|
||||
|
||||
Log.Debug("UiHide toggled: {0}", this.GameUiHidden);
|
||||
|
||||
return this.toggleUiHideHook.Original(thisPtr, unknownByte);
|
||||
return result;
|
||||
}
|
||||
|
||||
private char HandleImmDetour(IntPtr framework, char a2, byte a3)
|
||||
|
|
@ -513,8 +509,109 @@ public sealed unsafe class GameGui : IDisposable, IServiceType, IGameGui
|
|||
if (sourcePtr != null)
|
||||
this.utf8StringFromSequenceHook.Original(thisPtr, sourcePtr, sourceLen);
|
||||
else
|
||||
thisPtr->Ctor(); // this is in clientstructs but you could do it manually too
|
||||
thisPtr->Ctor(); // this is in ClientStructs but you could do it manually too
|
||||
|
||||
return thisPtr; // this function shouldn't need to return but the original asm moves this into rax before returning so be safe?
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plugin-scoped version of a AddonLifecycle service.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.ScopedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IGameGui>]
|
||||
#pragma warning restore SA1015
|
||||
internal class GameGuiPluginScoped : IDisposable, IServiceType, IGameGui
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly GameGui gameGuiService = Service<GameGui>.Get();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameGuiPluginScoped"/> class.
|
||||
/// </summary>
|
||||
internal GameGuiPluginScoped()
|
||||
{
|
||||
this.gameGuiService.UiHideToggled += this.UiHideToggledForward;
|
||||
this.gameGuiService.HoveredItemChanged += this.HoveredItemForward;
|
||||
this.gameGuiService.HoveredActionChanged += this.HoveredActionForward;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<bool>? UiHideToggled;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<ulong>? HoveredItemChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<HoveredAction>? HoveredActionChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool GameUiHidden => this.gameGuiService.GameUiHidden;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ulong HoveredItem
|
||||
{
|
||||
get => this.gameGuiService.HoveredItem;
|
||||
set => this.gameGuiService.HoveredItem = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public HoveredAction HoveredAction => this.gameGuiService.HoveredAction;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.gameGuiService.UiHideToggled -= this.UiHideToggledForward;
|
||||
this.gameGuiService.HoveredItemChanged -= this.HoveredItemForward;
|
||||
this.gameGuiService.HoveredActionChanged -= this.HoveredActionForward;
|
||||
|
||||
this.UiHideToggled = null;
|
||||
this.HoveredItemChanged = null;
|
||||
this.HoveredActionChanged = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool OpenMapWithMapLink(MapLinkPayload mapLink)
|
||||
=> this.gameGuiService.OpenMapWithMapLink(mapLink);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool WorldToScreen(Vector3 worldPos, out Vector2 screenPos)
|
||||
=> this.gameGuiService.WorldToScreen(worldPos, out screenPos);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool WorldToScreen(Vector3 worldPos, out Vector2 screenPos, out bool inView)
|
||||
=> this.gameGuiService.WorldToScreen(worldPos, out screenPos, out inView);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool ScreenToWorld(Vector2 screenPos, out Vector3 worldPos, float rayDistance = 100000)
|
||||
=> this.gameGuiService.ScreenToWorld(screenPos, out worldPos, rayDistance);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IntPtr GetUIModule()
|
||||
=> this.gameGuiService.GetUIModule();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IntPtr GetAddonByName(string name, int index = 1)
|
||||
=> this.gameGuiService.GetAddonByName(name, index);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IntPtr FindAgentInterface(string addonName)
|
||||
=> this.gameGuiService.FindAgentInterface(addonName);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public unsafe IntPtr FindAgentInterface(void* addon)
|
||||
=> this.gameGuiService.FindAgentInterface(addon);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IntPtr FindAgentInterface(IntPtr addonPtr)
|
||||
=> this.gameGuiService.FindAgentInterface(addonPtr);
|
||||
|
||||
private void UiHideToggledForward(object sender, bool toggled) => this.UiHideToggled?.Invoke(sender, toggled);
|
||||
|
||||
private void HoveredItemForward(object sender, ulong itemId) => this.HoveredItemChanged?.Invoke(sender, itemId);
|
||||
|
||||
private void HoveredActionForward(object sender, HoveredAction hoverAction) => this.HoveredActionChanged?.Invoke(sender, hoverAction);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.Game.Gui.PartyFinder;
|
||||
|
||||
/// <summary>
|
||||
/// The address resolver for the <see cref="PartyFinderGui"/> class.
|
||||
/// </summary>
|
||||
public class PartyFinderAddressResolver : BaseAddressResolver
|
||||
internal class PartyFinderAddressResolver : BaseAddressResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the address of the native ReceiveListing method.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Dalamud.Game.Gui.PartyFinder.Internal;
|
||||
|
|
@ -6,6 +5,7 @@ using Dalamud.Game.Gui.PartyFinder.Types;
|
|||
using Dalamud.Hooking;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Game.Gui.PartyFinder;
|
||||
|
|
@ -13,10 +13,9 @@ namespace Dalamud.Game.Gui.PartyFinder;
|
|||
/// <summary>
|
||||
/// This class handles interacting with the native PartyFinder window.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
public sealed class PartyFinderGui : IDisposable, IServiceType
|
||||
internal sealed class PartyFinderGui : IDisposable, IServiceType, IPartyFinderGui
|
||||
{
|
||||
private readonly PartyFinderAddressResolver address;
|
||||
private readonly IntPtr memory;
|
||||
|
|
@ -28,32 +27,21 @@ public sealed class PartyFinderGui : IDisposable, IServiceType
|
|||
/// </summary>
|
||||
/// <param name="sigScanner">Sig scanner to use.</param>
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private PartyFinderGui(SigScanner sigScanner)
|
||||
private PartyFinderGui(TargetSigScanner sigScanner)
|
||||
{
|
||||
this.address = new PartyFinderAddressResolver();
|
||||
this.address.Setup(sigScanner);
|
||||
|
||||
this.memory = Marshal.AllocHGlobal(PartyFinderPacket.PacketSize);
|
||||
|
||||
this.receiveListingHook = Hook<ReceiveListingDelegate>.FromAddress(this.address.ReceiveListing, new ReceiveListingDelegate(this.HandleReceiveListingDetour));
|
||||
this.receiveListingHook = Hook<ReceiveListingDelegate>.FromAddress(this.address.ReceiveListing, this.HandleReceiveListingDetour);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event type fired each time the game receives an individual Party Finder listing.
|
||||
/// Cannot modify listings but can hide them.
|
||||
/// </summary>
|
||||
/// <param name="listing">The listings received.</param>
|
||||
/// <param name="args">Additional arguments passed by the game.</param>
|
||||
public delegate void PartyFinderListingEventDelegate(PartyFinderListing listing, PartyFinderListingEventArgs args);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
private delegate void ReceiveListingDelegate(IntPtr managerPtr, IntPtr data);
|
||||
|
||||
/// <summary>
|
||||
/// Event fired each time the game receives an individual Party Finder listing.
|
||||
/// Cannot modify listings but can hide them.
|
||||
/// </summary>
|
||||
public event PartyFinderListingEventDelegate ReceiveListing;
|
||||
/// <inheritdoc/>
|
||||
public event IPartyFinderGui.PartyFinderListingEventDelegate? ReceiveListing;
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of managed and unmanaged resources.
|
||||
|
|
@ -138,3 +126,39 @@ public sealed class PartyFinderGui : IDisposable, IServiceType
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A scoped variant of the PartyFinderGui service.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.ScopedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IPartyFinderGui>]
|
||||
#pragma warning restore SA1015
|
||||
internal class PartyFinderGuiPluginScoped : IDisposable, IServiceType, IPartyFinderGui
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly PartyFinderGui partyFinderGuiService = Service<PartyFinderGui>.Get();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PartyFinderGuiPluginScoped"/> class.
|
||||
/// </summary>
|
||||
internal PartyFinderGuiPluginScoped()
|
||||
{
|
||||
this.partyFinderGuiService.ReceiveListing += this.ReceiveListingForward;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IPartyFinderGui.PartyFinderListingEventDelegate? ReceiveListing;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.partyFinderGuiService.ReceiveListing -= this.ReceiveListingForward;
|
||||
|
||||
this.ReceiveListing = null;
|
||||
}
|
||||
|
||||
private void ReceiveListingForward(PartyFinderListing listing, PartyFinderListingEventArgs args) => this.ReceiveListing?.Invoke(listing, args);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using Dalamud.Data;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
|
||||
namespace Dalamud.Game.Gui.PartyFinder.Types;
|
||||
|
|
@ -14,7 +14,7 @@ public static class JobFlagsExtensions
|
|||
/// <param name="job">A JobFlags enum member.</param>
|
||||
/// <param name="data">A DataManager to get the ClassJob from.</param>
|
||||
/// <returns>A ClassJob if found or null if not.</returns>
|
||||
public static ClassJob ClassJob(this JobFlags job, DataManager data)
|
||||
public static ClassJob? ClassJob(this JobFlags job, IDataManager data)
|
||||
{
|
||||
var jobs = data.GetExcelSheet<ClassJob>();
|
||||
|
||||
|
|
@ -52,6 +52,6 @@ public static class JobFlagsExtensions
|
|||
_ => null,
|
||||
};
|
||||
|
||||
return row == null ? null : jobs.GetRow((uint)row);
|
||||
return row == null ? null : jobs?.GetRow((uint)row);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
|
|
@ -6,16 +5,16 @@ using Dalamud.Game.Text.SeStringHandling;
|
|||
using Dalamud.Hooking;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
|
||||
namespace Dalamud.Game.Gui.Toast;
|
||||
|
||||
/// <summary>
|
||||
/// This class facilitates interacting with and creating native toast windows.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
public sealed partial class ToastGui : IDisposable, IServiceType
|
||||
internal sealed partial class ToastGui : IDisposable, IServiceType, IToastGui
|
||||
{
|
||||
private const uint QuestToastCheckmarkMagic = 60081;
|
||||
|
||||
|
|
@ -34,43 +33,16 @@ public sealed partial class ToastGui : IDisposable, IServiceType
|
|||
/// </summary>
|
||||
/// <param name="sigScanner">Sig scanner to use.</param>
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private ToastGui(SigScanner sigScanner)
|
||||
private ToastGui(TargetSigScanner sigScanner)
|
||||
{
|
||||
this.address = new ToastGuiAddressResolver();
|
||||
this.address.Setup(sigScanner);
|
||||
|
||||
this.showNormalToastHook = Hook<ShowNormalToastDelegate>.FromAddress(this.address.ShowNormalToast, new ShowNormalToastDelegate(this.HandleNormalToastDetour));
|
||||
this.showQuestToastHook = Hook<ShowQuestToastDelegate>.FromAddress(this.address.ShowQuestToast, new ShowQuestToastDelegate(this.HandleQuestToastDetour));
|
||||
this.showErrorToastHook = Hook<ShowErrorToastDelegate>.FromAddress(this.address.ShowErrorToast, new ShowErrorToastDelegate(this.HandleErrorToastDetour));
|
||||
this.showNormalToastHook = Hook<ShowNormalToastDelegate>.FromAddress(this.address.ShowNormalToast, this.HandleNormalToastDetour);
|
||||
this.showQuestToastHook = Hook<ShowQuestToastDelegate>.FromAddress(this.address.ShowQuestToast, this.HandleQuestToastDetour);
|
||||
this.showErrorToastHook = Hook<ShowErrorToastDelegate>.FromAddress(this.address.ShowErrorToast, this.HandleErrorToastDetour);
|
||||
}
|
||||
|
||||
#region Event delegates
|
||||
|
||||
/// <summary>
|
||||
/// A delegate type used when a normal toast window appears.
|
||||
/// </summary>
|
||||
/// <param name="message">The message displayed.</param>
|
||||
/// <param name="options">Assorted toast options.</param>
|
||||
/// <param name="isHandled">Whether the toast has been handled or should be propagated.</param>
|
||||
public delegate void OnNormalToastDelegate(ref SeString message, ref ToastOptions options, ref bool isHandled);
|
||||
|
||||
/// <summary>
|
||||
/// A delegate type used when a quest toast window appears.
|
||||
/// </summary>
|
||||
/// <param name="message">The message displayed.</param>
|
||||
/// <param name="options">Assorted toast options.</param>
|
||||
/// <param name="isHandled">Whether the toast has been handled or should be propagated.</param>
|
||||
public delegate void OnQuestToastDelegate(ref SeString message, ref QuestToastOptions options, ref bool isHandled);
|
||||
|
||||
/// <summary>
|
||||
/// A delegate type used when an error toast window appears.
|
||||
/// </summary>
|
||||
/// <param name="message">The message displayed.</param>
|
||||
/// <param name="isHandled">Whether the toast has been handled or should be propagated.</param>
|
||||
public delegate void OnErrorToastDelegate(ref SeString message, ref bool isHandled);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Marshal delegates
|
||||
|
||||
private delegate IntPtr ShowNormalToastDelegate(IntPtr manager, IntPtr text, int layer, byte isTop, byte isFast, int logMessageId);
|
||||
|
|
@ -82,21 +54,15 @@ public sealed partial class ToastGui : IDisposable, IServiceType
|
|||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IToastGui.OnNormalToastDelegate? Toast;
|
||||
|
||||
/// <summary>
|
||||
/// Event that will be fired when a toast is sent by the game or a plugin.
|
||||
/// </summary>
|
||||
public event OnNormalToastDelegate Toast;
|
||||
/// <inheritdoc/>
|
||||
public event IToastGui.OnQuestToastDelegate? QuestToast;
|
||||
|
||||
/// <summary>
|
||||
/// Event that will be fired when a quest toast is sent by the game or a plugin.
|
||||
/// </summary>
|
||||
public event OnQuestToastDelegate QuestToast;
|
||||
|
||||
/// <summary>
|
||||
/// Event that will be fired when an error toast is sent by the game or a plugin.
|
||||
/// </summary>
|
||||
public event OnErrorToastDelegate ErrorToast;
|
||||
/// <inheritdoc/>
|
||||
public event IToastGui.OnErrorToastDelegate? ErrorToast;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -172,31 +138,23 @@ public sealed partial class ToastGui : IDisposable, IServiceType
|
|||
/// <summary>
|
||||
/// Handles normal toasts.
|
||||
/// </summary>
|
||||
public sealed partial class ToastGui
|
||||
internal sealed partial class ToastGui
|
||||
{
|
||||
/// <summary>
|
||||
/// Show a toast message with the given content.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to be shown.</param>
|
||||
/// <param name="options">Options for the toast.</param>
|
||||
public void ShowNormal(string message, ToastOptions options = null)
|
||||
/// <inheritdoc/>
|
||||
public void ShowNormal(string message, ToastOptions? options = null)
|
||||
{
|
||||
options ??= new ToastOptions();
|
||||
this.normalQueue.Enqueue((Encoding.UTF8.GetBytes(message), options));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show a toast message with the given content.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to be shown.</param>
|
||||
/// <param name="options">Options for the toast.</param>
|
||||
public void ShowNormal(SeString message, ToastOptions options = null)
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ShowNormal(SeString message, ToastOptions? options = null)
|
||||
{
|
||||
options ??= new ToastOptions();
|
||||
this.normalQueue.Enqueue((message.Encode(), options));
|
||||
}
|
||||
|
||||
private void ShowNormal(byte[] bytes, ToastOptions options = null)
|
||||
private void ShowNormal(byte[] bytes, ToastOptions? options = null)
|
||||
{
|
||||
options ??= new ToastOptions();
|
||||
|
||||
|
|
@ -255,31 +213,23 @@ public sealed partial class ToastGui
|
|||
/// <summary>
|
||||
/// Handles quest toasts.
|
||||
/// </summary>
|
||||
public sealed partial class ToastGui
|
||||
internal sealed partial class ToastGui
|
||||
{
|
||||
/// <summary>
|
||||
/// Show a quest toast message with the given content.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to be shown.</param>
|
||||
/// <param name="options">Options for the toast.</param>
|
||||
public void ShowQuest(string message, QuestToastOptions options = null)
|
||||
/// <inheritdoc/>
|
||||
public void ShowQuest(string message, QuestToastOptions? options = null)
|
||||
{
|
||||
options ??= new QuestToastOptions();
|
||||
this.questQueue.Enqueue((Encoding.UTF8.GetBytes(message), options));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show a quest toast message with the given content.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to be shown.</param>
|
||||
/// <param name="options">Options for the toast.</param>
|
||||
public void ShowQuest(SeString message, QuestToastOptions options = null)
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ShowQuest(SeString message, QuestToastOptions? options = null)
|
||||
{
|
||||
options ??= new QuestToastOptions();
|
||||
this.questQueue.Enqueue((message.Encode(), options));
|
||||
}
|
||||
|
||||
private void ShowQuest(byte[] bytes, QuestToastOptions options = null)
|
||||
private void ShowQuest(byte[] bytes, QuestToastOptions? options = null)
|
||||
{
|
||||
options ??= new QuestToastOptions();
|
||||
|
||||
|
|
@ -365,21 +315,15 @@ public sealed partial class ToastGui
|
|||
/// <summary>
|
||||
/// Handles error toasts.
|
||||
/// </summary>
|
||||
public sealed partial class ToastGui
|
||||
internal sealed partial class ToastGui
|
||||
{
|
||||
/// <summary>
|
||||
/// Show an error toast message with the given content.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to be shown.</param>
|
||||
/// <inheritdoc/>
|
||||
public void ShowError(string message)
|
||||
{
|
||||
this.errorQueue.Enqueue(Encoding.UTF8.GetBytes(message));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show an error toast message with the given content.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to be shown.</param>
|
||||
/// <inheritdoc/>
|
||||
public void ShowError(SeString message)
|
||||
{
|
||||
this.errorQueue.Enqueue(message.Encode());
|
||||
|
|
@ -433,3 +377,76 @@ public sealed partial class ToastGui
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plugin scoped version of ToastGui.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.ScopedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IToastGui>]
|
||||
#pragma warning restore SA1015
|
||||
internal class ToastGuiPluginScoped : IDisposable, IServiceType, IToastGui
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly ToastGui toastGuiService = Service<ToastGui>.Get();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ToastGuiPluginScoped"/> class.
|
||||
/// </summary>
|
||||
internal ToastGuiPluginScoped()
|
||||
{
|
||||
this.toastGuiService.Toast += this.ToastForward;
|
||||
this.toastGuiService.QuestToast += this.QuestToastForward;
|
||||
this.toastGuiService.ErrorToast += this.ErrorToastForward;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IToastGui.OnNormalToastDelegate? Toast;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IToastGui.OnQuestToastDelegate? QuestToast;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IToastGui.OnErrorToastDelegate? ErrorToast;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.toastGuiService.Toast -= this.ToastForward;
|
||||
this.toastGuiService.QuestToast -= this.QuestToastForward;
|
||||
this.toastGuiService.ErrorToast -= this.ErrorToastForward;
|
||||
|
||||
this.Toast = null;
|
||||
this.QuestToast = null;
|
||||
this.ErrorToast = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ShowNormal(string message, ToastOptions? options = null) => this.toastGuiService.ShowNormal(message, options);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ShowNormal(SeString message, ToastOptions? options = null) => this.toastGuiService.ShowNormal(message, options);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ShowQuest(string message, QuestToastOptions? options = null) => this.toastGuiService.ShowQuest(message, options);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ShowQuest(SeString message, QuestToastOptions? options = null) => this.toastGuiService.ShowQuest(message, options);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ShowError(string message) => this.toastGuiService.ShowError(message);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ShowError(SeString message) => this.toastGuiService.ShowError(message);
|
||||
|
||||
private void ToastForward(ref SeString message, ref ToastOptions options, ref bool isHandled)
|
||||
=> this.Toast?.Invoke(ref message, ref options, ref isHandled);
|
||||
|
||||
private void QuestToastForward(ref SeString message, ref QuestToastOptions options, ref bool isHandled)
|
||||
=> this.QuestToast?.Invoke(ref message, ref options, ref isHandled);
|
||||
|
||||
private void ErrorToastForward(ref SeString message, ref bool isHandled)
|
||||
=> this.ErrorToast?.Invoke(ref message, ref isHandled);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.Game.Gui.Toast;
|
||||
|
||||
/// <summary>
|
||||
/// An address resolver for the <see cref="ToastGui"/> class.
|
||||
/// </summary>
|
||||
public class ToastGuiAddressResolver : BaseAddressResolver
|
||||
internal class ToastGuiAddressResolver : BaseAddressResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the address of the native ShowNormalToast method.
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ internal sealed partial class AntiDebug : IServiceType
|
|||
private IntPtr debugCheckAddress;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private AntiDebug(SigScanner sigScanner)
|
||||
private AntiDebug(TargetSigScanner sigScanner)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Game.Internal.DXGI;
|
||||
|
||||
/// <summary>
|
||||
/// The address resolver for native D3D11 methods to facilitate displaying the Dalamud UI.
|
||||
/// </summary>
|
||||
[Obsolete("This has been deprecated in favor of the VTable resolver.")]
|
||||
public sealed class SwapChainSigResolver : BaseAddressResolver, ISwapChainAddressResolver
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public IntPtr Present { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IntPtr ResizeBuffers { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Setup64Bit(SigScanner sig)
|
||||
{
|
||||
var module = Process.GetCurrentProcess().Modules.Cast<ProcessModule>().First(m => m.ModuleName == "dxgi.dll");
|
||||
|
||||
Log.Debug($"Found DXGI: 0x{module.BaseAddress.ToInt64():X}");
|
||||
|
||||
var scanner = new SigScanner(module);
|
||||
|
||||
// This(code after the function head - offset of it) was picked to avoid running into issues with other hooks being installed into this function.
|
||||
this.Present = scanner.ScanModule("41 8B F0 8B FA 89 54 24 ?? 48 8B D9 48 89 4D ?? C6 44 24 ?? 00") - 0x37;
|
||||
|
||||
this.ResizeBuffers = scanner.ScanModule("48 8B C4 55 41 54 41 55 41 56 41 57 48 8D 68 B1 48 81 EC ?? ?? ?? ?? 48 C7 45 ?? ?? ?? ?? ?? 48 89 58 10 48 89 70 18 48 89 78 20 45 8B F9 45 8B E0 44 8B EA 48 8B F9 8B 45 7F 89 44 24 30 8B 75 77 89 74 24 28 44 89 4C 24");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
|
@ -15,7 +14,7 @@ namespace Dalamud.Game.Internal.DXGI;
|
|||
/// <remarks>
|
||||
/// If the normal signature based method of resolution fails, this is the backup.
|
||||
/// </remarks>
|
||||
public class SwapChainVtableResolver : BaseAddressResolver, ISwapChainAddressResolver
|
||||
internal class SwapChainVtableResolver : BaseAddressResolver, ISwapChainAddressResolver
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public IntPtr Present { get; set; }
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ internal sealed unsafe partial class DalamudAtkTweaks : IServiceType
|
|||
private readonly string locDalamudSettings;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private DalamudAtkTweaks(SigScanner sigScanner)
|
||||
private DalamudAtkTweaks(TargetSigScanner sigScanner)
|
||||
{
|
||||
var openSystemMenuAddress = sigScanner.ScanText("E8 ?? ?? ?? ?? 32 C0 4C 8B AC 24 ?? ?? ?? ?? 48 8B 8D ?? ?? ?? ??");
|
||||
|
||||
|
|
|
|||
|
|
@ -17,14 +17,14 @@ namespace Dalamud.Game.Libc;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<ILibcFunction>]
|
||||
#pragma warning restore SA1015
|
||||
public sealed class LibcFunction : IServiceType, ILibcFunction
|
||||
internal sealed class LibcFunction : IServiceType, ILibcFunction
|
||||
{
|
||||
private readonly LibcFunctionAddressResolver address;
|
||||
private readonly StdStringFromCStringDelegate stdStringCtorCString;
|
||||
private readonly StdStringDeallocateDelegate stdStringDeallocate;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private LibcFunction(SigScanner sigScanner)
|
||||
private LibcFunction(TargetSigScanner sigScanner)
|
||||
{
|
||||
this.address = new LibcFunctionAddressResolver();
|
||||
this.address.Setup(sigScanner);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Dalamud.Game.Libc;
|
|||
/// <summary>
|
||||
/// The address resolver for the <see cref="LibcFunction"/> class.
|
||||
/// </summary>
|
||||
public sealed class LibcFunctionAddressResolver : BaseAddressResolver
|
||||
internal sealed class LibcFunctionAddressResolver : BaseAddressResolver
|
||||
{
|
||||
private delegate IntPtr StringFromCString();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Dalamud.Configuration.Internal;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
using Serilog;
|
||||
|
||||
|
|
@ -13,10 +13,9 @@ namespace Dalamud.Game.Network;
|
|||
/// <summary>
|
||||
/// This class handles interacting with game network events.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
public sealed class GameNetwork : IDisposable, IServiceType
|
||||
internal sealed class GameNetwork : IDisposable, IServiceType, IGameNetwork
|
||||
{
|
||||
private readonly GameNetworkAddressResolver address;
|
||||
private readonly Hook<ProcessZonePacketDownDelegate> processZonePacketDownHook;
|
||||
|
|
@ -31,7 +30,7 @@ public sealed class GameNetwork : IDisposable, IServiceType
|
|||
private IntPtr baseAddress;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private GameNetwork(SigScanner sigScanner)
|
||||
private GameNetwork(TargetSigScanner sigScanner)
|
||||
{
|
||||
this.hitchDetectorUp = new HitchDetector("GameNetworkUp", this.configuration.GameNetworkUpHitch);
|
||||
this.hitchDetectorDown = new HitchDetector("GameNetworkDown", this.configuration.GameNetworkDownHitch);
|
||||
|
|
@ -47,30 +46,16 @@ public sealed class GameNetwork : IDisposable, IServiceType
|
|||
this.processZonePacketUpHook = Hook<ProcessZonePacketUpDelegate>.FromAddress(this.address.ProcessZonePacketUp, this.ProcessZonePacketUpDetour);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The delegate type of a network message event.
|
||||
/// </summary>
|
||||
/// <param name="dataPtr">The pointer to the raw data.</param>
|
||||
/// <param name="opCode">The operation ID code.</param>
|
||||
/// <param name="sourceActorId">The source actor ID.</param>
|
||||
/// <param name="targetActorId">The taret actor ID.</param>
|
||||
/// <param name="direction">The direction of the packed.</param>
|
||||
public delegate void OnNetworkMessageDelegate(IntPtr dataPtr, ushort opCode, uint sourceActorId, uint targetActorId, NetworkMessageDirection direction);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
private delegate void ProcessZonePacketDownDelegate(IntPtr a, uint targetId, IntPtr dataPtr);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
private delegate byte ProcessZonePacketUpDelegate(IntPtr a1, IntPtr dataPtr, IntPtr a3, byte a4);
|
||||
|
||||
/// <summary>
|
||||
/// Event that is called when a network message is sent/received.
|
||||
/// </summary>
|
||||
public event OnNetworkMessageDelegate NetworkMessage;
|
||||
/// <inheritdoc/>
|
||||
public event IGameNetwork.OnNetworkMessageDelegate? NetworkMessage;
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
this.processZonePacketDownHook.Dispose();
|
||||
|
|
@ -154,3 +139,40 @@ public sealed class GameNetwork : IDisposable, IServiceType
|
|||
return this.processZonePacketUpHook.Original(a1, dataPtr, a3, a4);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plugin-scoped version of a AddonLifecycle service.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.ScopedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IGameNetwork>]
|
||||
#pragma warning restore SA1015
|
||||
internal class GameNetworkPluginScoped : IDisposable, IServiceType, IGameNetwork
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly GameNetwork gameNetworkService = Service<GameNetwork>.Get();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameNetworkPluginScoped"/> class.
|
||||
/// </summary>
|
||||
internal GameNetworkPluginScoped()
|
||||
{
|
||||
this.gameNetworkService.NetworkMessage += this.NetworkMessageForward;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event IGameNetwork.OnNetworkMessageDelegate? NetworkMessage;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.gameNetworkService.NetworkMessage -= this.NetworkMessageForward;
|
||||
|
||||
this.NetworkMessage = null;
|
||||
}
|
||||
|
||||
private void NetworkMessageForward(nint dataPtr, ushort opCode, uint sourceActorId, uint targetActorId, NetworkMessageDirection direction)
|
||||
=> this.NetworkMessage?.Invoke(dataPtr, opCode, sourceActorId, targetActorId, direction);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.Game.Network;
|
||||
|
||||
/// <summary>
|
||||
/// The address resolver for the <see cref="GameNetwork"/> class.
|
||||
/// </summary>
|
||||
public sealed class GameNetworkAddressResolver : BaseAddressResolver
|
||||
internal sealed class GameNetworkAddressResolver : BaseAddressResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the address of the ProcessZonePacketDown method.
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ internal class NetworkHandlers : IDisposable, IServiceType
|
|||
private NetworkHandlers(GameNetwork gameNetwork)
|
||||
{
|
||||
this.uploader = new UniversalisMarketBoardUploader();
|
||||
this.CfPop = (_, _) => { };
|
||||
this.CfPop = _ => { };
|
||||
|
||||
this.messages = Observable.Create<NetworkMessage>(observer =>
|
||||
{
|
||||
|
|
@ -75,7 +75,7 @@ internal class NetworkHandlers : IDisposable, IServiceType
|
|||
/// <summary>
|
||||
/// Event which gets fired when a duty is ready.
|
||||
/// </summary>
|
||||
public event EventHandler<ContentFinderCondition> CfPop;
|
||||
public event Action<ContentFinderCondition> CfPop;
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of managed and unmanaged resources.
|
||||
|
|
@ -430,7 +430,7 @@ internal class NetworkHandlers : IDisposable, IServiceType
|
|||
Service<ChatGui>.GetNullable()?.Print($"Duty pop: {cfcName}");
|
||||
}
|
||||
|
||||
this.CfPop.InvokeSafely(this, cfCondition);
|
||||
this.CfPop.InvokeSafely(cfCondition);
|
||||
}).ContinueWith(
|
||||
task => Log.Error(task.Exception, "CfPop.Invoke failed"),
|
||||
TaskContinuationOptions.OnlyOnFaulted);
|
||||
|
|
|
|||
|
|
@ -20,12 +20,7 @@ namespace Dalamud.Game;
|
|||
/// <summary>
|
||||
/// A SigScanner facilitates searching for memory signatures in a given ProcessModule.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<ISigScanner>]
|
||||
#pragma warning restore SA1015
|
||||
public class SigScanner : IDisposable, IServiceType, ISigScanner
|
||||
public class SigScanner : IDisposable, ISigScanner
|
||||
{
|
||||
private readonly FileInfo? cacheFile;
|
||||
|
||||
|
|
|
|||
29
Dalamud/Game/TargetSigScanner.cs
Normal file
29
Dalamud/Game/TargetSigScanner.cs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
|
||||
namespace Dalamud.Game;
|
||||
|
||||
/// <summary>
|
||||
/// A SigScanner facilitates searching for memory signatures in a given ProcessModule.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.Service]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<ISigScanner>]
|
||||
#pragma warning restore SA1015
|
||||
internal class TargetSigScanner : SigScanner, IServiceType
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TargetSigScanner"/> class.
|
||||
/// </summary>
|
||||
/// <param name="doCopy">Whether or not to copy the module upon initialization for search operations to use, as to not get disturbed by possible hooks.</param>
|
||||
/// <param name="cacheFile">File used to cached signatures.</param>
|
||||
public TargetSigScanner(bool doCopy = false, FileInfo? cacheFile = null)
|
||||
: base(Process.GetCurrentProcess().MainModule!, doCopy, cacheFile)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ using System.IO;
|
|||
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
|
||||
|
|
@ -27,12 +28,6 @@ public abstract partial class Payload
|
|||
// To force-invalidate it, Dirty can be set to true
|
||||
private byte[] encodedData;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Lumina instance to use for any necessary data lookups.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public DataManager DataResolver => Service<DataManager>.Get();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of this payload.
|
||||
/// </summary>
|
||||
|
|
@ -43,6 +38,13 @@ public abstract partial class Payload
|
|||
/// </summary>
|
||||
public bool Dirty { get; protected set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Lumina instance to use for any necessary data lookups.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
// TODO: We should refactor this. It should not be possible to get IDataManager through here.
|
||||
protected IDataManager DataResolver => Service<DataManager>.Get();
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a binary representation of a payload into its corresponding nice object payload.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -130,7 +130,13 @@ public class MapLinkPayload : Payload
|
|||
var y = Math.Truncate((this.YCoord + fudge) * 10.0f) / 10.0f;
|
||||
|
||||
// the formatting and spacing the game uses
|
||||
return $"( {x:0.0} , {y:0.0} )";
|
||||
var clientState = Service<ClientState.ClientState>.Get();
|
||||
return clientState.ClientLanguage switch
|
||||
{
|
||||
ClientLanguage.German => $"( {x:0.0}, {y:0.0} )",
|
||||
ClientLanguage.Japanese => $"({x:0.0}, {y:0.0})",
|
||||
_ => $"( {x:0.0} , {y:0.0} )",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,14 +52,27 @@ public class SeString
|
|||
/// with the appropriate glow and coloring.
|
||||
/// </summary>
|
||||
/// <returns>A list of all the payloads required to insert the link marker.</returns>
|
||||
public static IEnumerable<Payload> TextArrowPayloads => new List<Payload>(new Payload[]
|
||||
public static IEnumerable<Payload> TextArrowPayloads
|
||||
{
|
||||
new UIForegroundPayload(0x01F4),
|
||||
new UIGlowPayload(0x01F5),
|
||||
new TextPayload($"{(char)SeIconChar.LinkMarker}"),
|
||||
UIGlowPayload.UIGlowOff,
|
||||
UIForegroundPayload.UIForegroundOff,
|
||||
});
|
||||
get
|
||||
{
|
||||
var clientState = Service<ClientState.ClientState>.Get();
|
||||
var markerSpace = clientState.ClientLanguage switch
|
||||
{
|
||||
ClientLanguage.German => " ",
|
||||
ClientLanguage.French => " ",
|
||||
_ => string.Empty,
|
||||
};
|
||||
return new List<Payload>
|
||||
{
|
||||
new UIForegroundPayload(500),
|
||||
new UIGlowPayload(501),
|
||||
new TextPayload($"{(char)SeIconChar.LinkMarker}{markerSpace}"),
|
||||
UIGlowPayload.UIGlowOff,
|
||||
UIForegroundPayload.UIForegroundOff,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an empty SeString.
|
||||
|
|
@ -171,6 +184,7 @@ public class SeString
|
|||
var data = Service<DataManager>.Get();
|
||||
|
||||
var displayName = displayNameOverride;
|
||||
var rarity = 1; // default: white
|
||||
if (displayName == null)
|
||||
{
|
||||
switch (kind)
|
||||
|
|
@ -178,7 +192,9 @@ public class SeString
|
|||
case ItemPayload.ItemKind.Normal:
|
||||
case ItemPayload.ItemKind.Collectible:
|
||||
case ItemPayload.ItemKind.Hq:
|
||||
displayName = data.GetExcelSheet<Item>()?.GetRow(itemId)?.Name;
|
||||
var item = data.GetExcelSheet<Item>()?.GetRow(itemId);
|
||||
displayName = item?.Name;
|
||||
rarity = item?.Rarity ?? 1;
|
||||
break;
|
||||
case ItemPayload.ItemKind.EventItem:
|
||||
displayName = data.GetExcelSheet<EventItem>()?.GetRow(itemId)?.Name;
|
||||
|
|
@ -202,21 +218,20 @@ public class SeString
|
|||
displayName += $" {(char)SeIconChar.Collectible}";
|
||||
}
|
||||
|
||||
// TODO: probably a cleaner way to build these than doing the bulk+insert
|
||||
var payloads = new List<Payload>(new Payload[]
|
||||
{
|
||||
new UIForegroundPayload(0x0225),
|
||||
new UIGlowPayload(0x0226),
|
||||
new ItemPayload(itemId, kind),
|
||||
// arrow goes here
|
||||
new TextPayload(displayName),
|
||||
RawPayload.LinkTerminator,
|
||||
// sometimes there is another set of uiglow/foreground off payloads here
|
||||
// might be necessary when including additional text after the item name
|
||||
});
|
||||
payloads.InsertRange(3, TextArrowPayloads);
|
||||
var textColor = (ushort)(549 + ((rarity - 1) * 2));
|
||||
var textGlowColor = (ushort)(textColor + 1);
|
||||
|
||||
return new SeString(payloads);
|
||||
// Note: `SeStringBuilder.AddItemLink` uses this function, so don't call it here!
|
||||
return new SeStringBuilder()
|
||||
.AddUiForeground(textColor)
|
||||
.AddUiGlow(textGlowColor)
|
||||
.Add(new ItemPayload(itemId, kind))
|
||||
.Append(TextArrowPayloads)
|
||||
.AddText(displayName)
|
||||
.AddUiGlowOff()
|
||||
.AddUiForegroundOff()
|
||||
.Add(RawPayload.LinkTerminator)
|
||||
.Build();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -406,7 +421,7 @@ public class SeString
|
|||
/// </summary>
|
||||
/// <param name="payloads">The Payloads to append.</param>
|
||||
/// <returns>This object.</returns>
|
||||
public SeString Append(List<Payload> payloads)
|
||||
public SeString Append(IEnumerable<Payload> payloads)
|
||||
{
|
||||
this.Payloads.AddRange(payloads);
|
||||
return this;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
|
||||
namespace Dalamud.Game.Text.SeStringHandling;
|
||||
|
|
@ -30,6 +33,17 @@ public class SeStringBuilder
|
|||
/// <returns>The current builder.</returns>
|
||||
public SeStringBuilder Append(string text) => this.AddText(text);
|
||||
|
||||
/// <summary>
|
||||
/// Append payloads to the builder.
|
||||
/// </summary>
|
||||
/// <param name="payloads">A list of payloads.</param>
|
||||
/// <returns>The current builder.</returns>
|
||||
public SeStringBuilder Append(IEnumerable<Payload> payloads)
|
||||
{
|
||||
this.BuiltString.Payloads.AddRange(payloads);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append raw text to the builder.
|
||||
/// </summary>
|
||||
|
|
@ -104,7 +118,7 @@ public class SeStringBuilder
|
|||
/// <param name="itemNameOverride">Override for the item's name.</param>
|
||||
/// <returns>The current builder.</returns>
|
||||
public SeStringBuilder AddItemLink(uint itemId, bool isHq, string? itemNameOverride = null) =>
|
||||
this.Add(new ItemPayload(itemId, isHq, itemNameOverride));
|
||||
this.Append(SeString.CreateItemLink(itemId, isHq, itemNameOverride));
|
||||
|
||||
/// <summary>
|
||||
/// Add an item link to the builder.
|
||||
|
|
@ -113,14 +127,15 @@ public class SeStringBuilder
|
|||
/// <param name="kind">Kind of item to encode.</param>
|
||||
/// <param name="itemNameOverride">Override for the item's name.</param>
|
||||
/// <returns>The current builder.</returns>
|
||||
public SeStringBuilder AddItemLink(uint itemId, ItemPayload.ItemKind kind, string? itemNameOverride = null) =>
|
||||
this.Add(new ItemPayload(itemId, kind, itemNameOverride));
|
||||
public SeStringBuilder AddItemLink(uint itemId, ItemPayload.ItemKind kind = ItemPayload.ItemKind.Normal, string? itemNameOverride = null) =>
|
||||
this.Append(SeString.CreateItemLink(itemId, kind, itemNameOverride));
|
||||
|
||||
/// <summary>
|
||||
/// Add an item link to the builder.
|
||||
/// </summary>
|
||||
/// <param name="rawItemId">The raw item ID.</param>
|
||||
/// <returns>The current builder.</returns>
|
||||
/// <remarks>To terminate this item link, add a <see cref="RawPayload.LinkTerminator"/>.</remarks>
|
||||
public SeStringBuilder AddItemLinkRaw(uint rawItemId) =>
|
||||
this.Add(ItemPayload.FromRaw(rawItemId));
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue