diff --git a/Dalamud.Boot/Dalamud.Boot.vcxproj b/Dalamud.Boot/Dalamud.Boot.vcxproj
index ea263d7f9..298edbcbc 100644
--- a/Dalamud.Boot/Dalamud.Boot.vcxproj
+++ b/Dalamud.Boot/Dalamud.Boot.vcxproj
@@ -32,6 +32,9 @@
obj\$(Configuration)\
+
+
+
true
$(SolutionDir)bin\lib\$(Configuration)\libMinHook\;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)
@@ -55,7 +58,7 @@
Windows
true
false
- Version.lib;%(AdditionalDependencies)
+ Version.lib;Shlwapi.lib;%(AdditionalDependencies)
..\lib\CoreCLR;%(AdditionalLibraryDirectories)
@@ -70,6 +73,7 @@
false
false
+ module.def
@@ -83,9 +87,13 @@
true
true
+ module.def
+
+
+
nethost.dll
@@ -129,6 +137,7 @@
NotUsing
NotUsing
+
NotUsing
NotUsing
@@ -168,6 +177,7 @@
+
@@ -181,8 +191,14 @@
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/Dalamud.Boot/Dalamud.Boot.vcxproj.filters b/Dalamud.Boot/Dalamud.Boot.vcxproj.filters
index 8b4483684..87eaf6fcc 100644
--- a/Dalamud.Boot/Dalamud.Boot.vcxproj.filters
+++ b/Dalamud.Boot/Dalamud.Boot.vcxproj.filters
@@ -73,6 +73,9 @@
Dalamud.Boot DLL
+
+ Dalamud.Boot DLL
+
@@ -140,6 +143,9 @@
+
+ Dalamud.Boot DLL
+
@@ -147,4 +153,14 @@
+
+
+ Dalamud.Boot DLL
+
+
+
+
+ Dalamud.Boot DLL
+
+
\ No newline at end of file
diff --git a/Dalamud.Boot/DalamudStartInfo.cpp b/Dalamud.Boot/DalamudStartInfo.cpp
index d20265bf8..f5632a2ea 100644
--- a/Dalamud.Boot/DalamudStartInfo.cpp
+++ b/Dalamud.Boot/DalamudStartInfo.cpp
@@ -89,13 +89,16 @@ void from_json(const nlohmann::json& json, DalamudStartInfo& config) {
config.DalamudLoadMethod = json.value("LoadMethod", config.DalamudLoadMethod);
config.WorkingDirectory = json.value("WorkingDirectory", config.WorkingDirectory);
config.ConfigurationPath = json.value("ConfigurationPath", config.ConfigurationPath);
+ config.LogPath = json.value("LogPath", config.LogPath);
+ config.LogName = json.value("LogName", config.LogName);
config.PluginDirectory = json.value("PluginDirectory", config.PluginDirectory);
- config.DefaultPluginDirectory = json.value("DefaultPluginDirectory", config.DefaultPluginDirectory);
config.AssetDirectory = json.value("AssetDirectory", config.AssetDirectory);
config.Language = json.value("Language", config.Language);
config.GameVersion = json.value("GameVersion", config.GameVersion);
- config.DelayInitializeMs = json.value("DelayInitializeMs", config.DelayInitializeMs);
config.TroubleshootingPackData = json.value("TroubleshootingPackData", std::string{});
+ config.DelayInitializeMs = json.value("DelayInitializeMs", config.DelayInitializeMs);
+ config.NoLoadPlugins = json.value("NoLoadPlugins", config.NoLoadPlugins);
+ config.NoLoadThirdPartyPlugins = json.value("NoLoadThirdPartyPlugins", config.NoLoadThirdPartyPlugins);
config.BootLogPath = json.value("BootLogPath", config.BootLogPath);
config.BootShowConsole = json.value("BootShowConsole", config.BootShowConsole);
diff --git a/Dalamud.Boot/DalamudStartInfo.h b/Dalamud.Boot/DalamudStartInfo.h
index 5cee8f16b..e6cc54ab0 100644
--- a/Dalamud.Boot/DalamudStartInfo.h
+++ b/Dalamud.Boot/DalamudStartInfo.h
@@ -35,13 +35,16 @@ struct DalamudStartInfo {
LoadMethod DalamudLoadMethod = LoadMethod::Entrypoint;
std::string WorkingDirectory;
std::string ConfigurationPath;
+ std::string LogPath;
+ std::string LogName;
std::string PluginDirectory;
- std::string DefaultPluginDirectory;
std::string AssetDirectory;
ClientLanguage Language = ClientLanguage::English;
std::string GameVersion;
- int DelayInitializeMs = 0;
std::string TroubleshootingPackData;
+ int DelayInitializeMs = 0;
+ bool NoLoadPlugins;
+ bool NoLoadThirdPartyPlugins;
std::string BootLogPath;
bool BootShowConsole = false;
diff --git a/Dalamud.Boot/dllmain.cpp b/Dalamud.Boot/dllmain.cpp
index 2566016e8..e6aa9c4ac 100644
--- a/Dalamud.Boot/dllmain.cpp
+++ b/Dalamud.Boot/dllmain.cpp
@@ -9,7 +9,7 @@
HMODULE g_hModule;
HINSTANCE g_hGameInstance = GetModuleHandleW(nullptr);
-DWORD WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
+HRESULT WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
g_startInfo.from_envvars();
std::string jsonParseError;
@@ -114,7 +114,7 @@ DWORD WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
logging::I("Calling InitializeClrAndGetEntryPoint");
void* entrypoint_vfn;
- int result = InitializeClrAndGetEntryPoint(
+ const auto result = InitializeClrAndGetEntryPoint(
g_hModule,
g_startInfo.BootEnableEtw,
runtimeconfig_path,
@@ -124,7 +124,7 @@ DWORD WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
L"Dalamud.EntryPoint+InitDelegate, Dalamud",
&entrypoint_vfn);
- if (result != 0)
+ if (FAILED(result))
return result;
using custom_component_entry_point_fn = void (CORECLR_DELEGATE_CALLTYPE*)(LPVOID, HANDLE);
@@ -156,10 +156,10 @@ DWORD WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
entrypoint_fn(lpParam, hMainThreadContinue);
logging::I("Done!");
- return 0;
+ return S_OK;
}
-DllExport DWORD WINAPI Initialize(LPVOID lpParam) {
+extern "C" DWORD WINAPI Initialize(LPVOID lpParam) {
return InitializeImpl(lpParam, CreateEvent(nullptr, TRUE, FALSE, nullptr));
}
diff --git a/Dalamud.Boot/hooks.cpp b/Dalamud.Boot/hooks.cpp
index 7cf489195..1b1280cf0 100644
--- a/Dalamud.Boot/hooks.cpp
+++ b/Dalamud.Boot/hooks.cpp
@@ -2,39 +2,9 @@
#include "hooks.h"
+#include "ntdll.h"
#include "logging.h"
-enum {
- LDR_DLL_NOTIFICATION_REASON_LOADED = 1,
- LDR_DLL_NOTIFICATION_REASON_UNLOADED = 2,
-};
-
-struct LDR_DLL_UNLOADED_NOTIFICATION_DATA {
- ULONG Flags; //Reserved.
- const UNICODE_STRING* FullDllName; //The full path name of the DLL module.
- const UNICODE_STRING* BaseDllName; //The base file name of the DLL module.
- PVOID DllBase; //A pointer to the base address for the DLL in memory.
- ULONG SizeOfImage; //The size of the DLL image, in bytes.
-};
-
-struct LDR_DLL_LOADED_NOTIFICATION_DATA {
- ULONG Flags; //Reserved.
- const UNICODE_STRING* FullDllName; //The full path name of the DLL module.
- const UNICODE_STRING* BaseDllName; //The base file name of the DLL module.
- PVOID DllBase; //A pointer to the base address for the DLL in memory.
- ULONG SizeOfImage; //The size of the DLL image, in bytes.
-};
-
-union LDR_DLL_NOTIFICATION_DATA {
- LDR_DLL_LOADED_NOTIFICATION_DATA Loaded;
- LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded;
-};
-
-using PLDR_DLL_NOTIFICATION_FUNCTION = VOID CALLBACK(_In_ ULONG NotificationReason, _In_ const LDR_DLL_NOTIFICATION_DATA* NotificationData, _In_opt_ PVOID Context);
-
-static const auto LdrRegisterDllNotification = utils::loaded_module(GetModuleHandleW(L"ntdll.dll")).get_exported_function("LdrRegisterDllNotification");
-static const auto LdrUnregisterDllNotification = utils::loaded_module(GetModuleHandleW(L"ntdll.dll")).get_exported_function("LdrUnregisterDllNotification");
-
hooks::getprocaddress_singleton_import_hook::getprocaddress_singleton_import_hook()
: m_pfnGetProcAddress(GetProcAddress)
, m_thunk("kernel32!GetProcAddress(Singleton Import Hook)",
diff --git a/Dalamud.Boot/hooks.h b/Dalamud.Boot/hooks.h
index ad3b2cc6c..f6ad370d1 100644
--- a/Dalamud.Boot/hooks.h
+++ b/Dalamud.Boot/hooks.h
@@ -1,6 +1,5 @@
#pragma once
-#include
#include
-
+
diff --git a/Dalamud.Injector.Boot/main.cpp b/Dalamud.Injector.Boot/main.cpp
index 741505d08..7fc44f5e1 100644
--- a/Dalamud.Injector.Boot/main.cpp
+++ b/Dalamud.Injector.Boot/main.cpp
@@ -23,7 +23,7 @@ int wmain(int argc, wchar_t** argv)
// =========================================================================== //
void* entrypoint_vfn;
- int result = InitializeClrAndGetEntryPoint(
+ const auto result = InitializeClrAndGetEntryPoint(
GetModuleHandleW(nullptr),
false,
runtimeconfig_path,
@@ -33,15 +33,15 @@ int wmain(int argc, wchar_t** argv)
L"Dalamud.Injector.EntryPoint+MainDelegate, Dalamud.Injector",
&entrypoint_vfn);
- if (result != 0)
+ if (FAILED(result))
return result;
- typedef void (CORECLR_DELEGATE_CALLTYPE* custom_component_entry_point_fn)(int, wchar_t**);
+ typedef int (CORECLR_DELEGATE_CALLTYPE* custom_component_entry_point_fn)(int, wchar_t**);
custom_component_entry_point_fn entrypoint_fn = reinterpret_cast(entrypoint_vfn);
logging::I("Running Dalamud Injector...");
- entrypoint_fn(argc, argv);
+ const auto ret = entrypoint_fn(argc, argv);
logging::I("Done!");
- return 0;
+ return ret;
}
diff --git a/Dalamud.Injector/EntryPoint.cs b/Dalamud.Injector/EntryPoint.cs
index f839d9656..9085eae04 100644
--- a/Dalamud.Injector/EntryPoint.cs
+++ b/Dalamud.Injector/EntryPoint.cs
@@ -31,89 +31,100 @@ namespace Dalamud.Injector
///
/// Count of arguments.
/// char** string arguments.
- public delegate void MainDelegate(int argc, IntPtr argvPtr);
+ /// Return value (HRESULT).
+ public delegate int MainDelegate(int argc, IntPtr argvPtr);
///
/// Start the Dalamud injector.
///
/// Count of arguments.
/// byte** string arguments.
- public static void Main(int argc, IntPtr argvPtr)
+ /// Return value (HRESULT).
+ public static int Main(int argc, IntPtr argvPtr)
{
- List args = new(argc);
-
- unsafe
+ try
{
- var argv = (IntPtr*)argvPtr;
- for (var i = 0; i < argc; i++)
- args.Add(Marshal.PtrToStringUni(argv[i]));
- }
+ List args = new(argc);
- Init(args);
- args.Remove("-v"); // Remove "verbose" flag
-
- if (args.Count >= 2 && args[1].ToLowerInvariant() == "launch-test")
- {
- Environment.Exit(ProcessLaunchTestCommand(args));
- return;
- }
-
- DalamudStartInfo startInfo = null;
- if (args.Count == 1)
- {
- // No command defaults to inject
- args.Add("inject");
- args.Add("--all");
-
-#if !DEBUG
- args.Add("--warn");
-#endif
-
- }
- else if (int.TryParse(args[1], out var _))
- {
- // Assume that PID has been passed.
- args.Insert(1, "inject");
-
- // If originally second parameter exists, then assume that it's a base64 encoded start info.
- // Dalamud.Injector.exe inject [pid] [base64]
- if (args.Count == 4)
+ unsafe
{
- startInfo = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(Convert.FromBase64String(args[3])));
- args.RemoveAt(3);
+ var argv = (IntPtr*)argvPtr;
+ for (var i = 0; i < argc; i++)
+ args.Add(Marshal.PtrToStringUni(argv[i]));
+ }
+
+ Init(args);
+ args.Remove("-v"); // Remove "verbose" flag
+
+ if (args.Count >= 2 && args[1].ToLowerInvariant() == "launch-test")
+ {
+ return ProcessLaunchTestCommand(args);
+ }
+
+ DalamudStartInfo startInfo = null;
+ if (args.Count == 1)
+ {
+ // No command defaults to inject
+ args.Add("inject");
+ args.Add("--all");
+
+ #if !DEBUG
+ args.Add("--warn");
+ #endif
+
+ }
+ else if (int.TryParse(args[1], out var _))
+ {
+ // Assume that PID has been passed.
+ args.Insert(1, "inject");
+
+ // If originally second parameter exists, then assume that it's a base64 encoded start info.
+ // Dalamud.Injector.exe inject [pid] [base64]
+ if (args.Count == 4)
+ {
+ startInfo = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(Convert.FromBase64String(args[3])));
+ args.RemoveAt(3);
+ }
+ }
+
+ startInfo = ExtractAndInitializeStartInfoFromArguments(startInfo, args);
+ // Remove already handled arguments
+ args.Remove("--console");
+ args.Remove("--msgbox1");
+ args.Remove("--msgbox2");
+ args.Remove("--msgbox3");
+ args.Remove("--etw");
+ args.Remove("--veh");
+ args.Remove("--veh-full");
+ args.Remove("--no-plugin");
+ args.Remove("--no-3rd-plugin");
+ args.Remove("--crash-handler-console");
+ args.Remove("--no-exception-handlers");
+
+ var mainCommand = args[1].ToLowerInvariant();
+ if (mainCommand.Length > 0 && mainCommand.Length <= 6 && "inject"[..mainCommand.Length] == mainCommand)
+ {
+ return ProcessInjectCommand(args, startInfo);
+ }
+ else if (mainCommand.Length > 0 && mainCommand.Length <= 6 &&
+ "launch"[..mainCommand.Length] == mainCommand)
+ {
+ return ProcessLaunchCommand(args, startInfo);
+ }
+ else if (mainCommand.Length > 0 && mainCommand.Length <= 4 &&
+ "help"[..mainCommand.Length] == mainCommand)
+ {
+ return ProcessHelpCommand(args, args.Count >= 3 ? args[2] : null);
+ }
+ else
+ {
+ throw new CommandLineException($"\"{mainCommand}\" is not a valid command.");
}
}
-
- startInfo = ExtractAndInitializeStartInfoFromArguments(startInfo, args);
- // Remove already handled arguments
- args.Remove("--console");
- args.Remove("--msgbox1");
- args.Remove("--msgbox2");
- args.Remove("--msgbox3");
- args.Remove("--etw");
- args.Remove("--veh");
- args.Remove("--veh-full");
- args.Remove("--no-plugin");
- args.Remove("--no-3rd-plugin");
- args.Remove("--crash-handler-console");
- args.Remove("--no-exception-handlers");
-
- var mainCommand = args[1].ToLowerInvariant();
- if (mainCommand.Length > 0 && mainCommand.Length <= 6 && "inject"[..mainCommand.Length] == mainCommand)
+ catch (Exception e)
{
- Environment.Exit(ProcessInjectCommand(args, startInfo));
- }
- else if (mainCommand.Length > 0 && mainCommand.Length <= 6 && "launch"[..mainCommand.Length] == mainCommand)
- {
- Environment.Exit(ProcessLaunchCommand(args, startInfo));
- }
- else if (mainCommand.Length > 0 && mainCommand.Length <= 4 && "help"[..mainCommand.Length] == mainCommand)
- {
- Environment.Exit(ProcessHelpCommand(args, args.Count >= 3 ? args[2] : null));
- }
- else
- {
- throw new CommandLineException($"\"{mainCommand}\" is not a valid command.");
+ Log.Error(e, "Operation failed.");
+ return e.HResult;
}
}
@@ -189,6 +200,7 @@ namespace Dalamud.Injector
CullLogFile(logPath, 1 * 1024 * 1024);
Log.Logger = new LoggerConfiguration()
+ .WriteTo.Console(standardErrorFromLevel: LogEventLevel.Debug)
.WriteTo.File(logPath, fileSizeLimitBytes: null)
.MinimumLevel.ControlledBy(levelSwitch)
.CreateLogger();
@@ -377,12 +389,22 @@ namespace Dalamud.Injector
#else
startInfo.LogPath ??= xivlauncherDir;
#endif
+ startInfo.LogName ??= string.Empty;
// Set boot defaults
startInfo.BootShowConsole = args.Contains("--console");
startInfo.BootEnableEtw = args.Contains("--etw");
startInfo.BootLogPath = GetLogPath(startInfo.LogPath, "dalamud.boot", startInfo.LogName);
- startInfo.BootEnabledGameFixes = new List { "prevent_devicechange_crashes", "disable_game_openprocess_access_check", "redirect_openprocess", "backup_userdata_save", "prevent_icmphandle_crashes" };
+ startInfo.BootEnabledGameFixes = new()
+ {
+ // See: xivfixes.h, xivfixes.cpp
+ "prevent_devicechange_crashes",
+ "disable_game_openprocess_access_check",
+ "redirect_openprocess",
+ "backup_userdata_save",
+ "prevent_icmphandle_crashes",
+ "symbol_load_patches",
+ };
startInfo.BootDotnetOpenProcessHookMode = 0;
startInfo.BootWaitMessageBox |= args.Contains("--msgbox1") ? 1 : 0;
startInfo.BootWaitMessageBox |= args.Contains("--msgbox2") ? 2 : 0;
@@ -800,12 +822,8 @@ namespace Dalamud.Injector
{
var startInfo = AdjustStartInfo(dalamudStartInfo, gamePath);
Log.Information("Using start info: {0}", JsonConvert.SerializeObject(startInfo));
- if (RewriteRemoteEntryPointW(p.Handle, gamePath, JsonConvert.SerializeObject(startInfo)) != 0)
- {
- Log.Error("[HOOKS] RewriteRemoteEntryPointW failed");
- throw new Exception("RewriteRemoteEntryPointW failed");
- }
-
+ Marshal.ThrowExceptionForHR(
+ RewriteRemoteEntryPointW(p.Handle, gamePath, JsonConvert.SerializeObject(startInfo)));
Log.Verbose("RewriteRemoteEntryPointW called!");
}
},
diff --git a/Dalamud.sln b/Dalamud.sln
index 200238a83..93089b9a6 100644
--- a/Dalamud.sln
+++ b/Dalamud.sln
@@ -6,8 +6,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
- targets\Dalamud.Plugin.targets = targets\Dalamud.Plugin.targets
targets\Dalamud.Plugin.Bootstrap.targets = targets\Dalamud.Plugin.Bootstrap.targets
+ targets\Dalamud.Plugin.targets = targets\Dalamud.Plugin.targets
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "build", "build\build.csproj", "{94E5B016-02B1-459B-97D9-E783F28764B2}"
@@ -38,184 +38,70 @@ 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.Common", "Dalamud.Common\Dalamud.Common.csproj", "{F21B13D2-D7D0-4456-B70F-3F8D695064E2}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dalamud.Common", "Dalamud.Common\Dalamud.Common.csproj", "{F21B13D2-D7D0-4456-B70F-3F8D695064E2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
- Release|x64 = Release|x64
- Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{94E5B016-02B1-459B-97D9-E783F28764B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{94E5B016-02B1-459B-97D9-E783F28764B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {94E5B016-02B1-459B-97D9-E783F28764B2}.Debug|x64.ActiveCfg = Debug|Any CPU
- {94E5B016-02B1-459B-97D9-E783F28764B2}.Debug|x64.Build.0 = Debug|Any CPU
- {94E5B016-02B1-459B-97D9-E783F28764B2}.Debug|x86.ActiveCfg = Debug|Any CPU
{94E5B016-02B1-459B-97D9-E783F28764B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{94E5B016-02B1-459B-97D9-E783F28764B2}.Release|Any CPU.Build.0 = Release|Any CPU
- {94E5B016-02B1-459B-97D9-E783F28764B2}.Release|x64.ActiveCfg = Release|Any CPU
- {94E5B016-02B1-459B-97D9-E783F28764B2}.Release|x64.Build.0 = Release|Any CPU
- {94E5B016-02B1-459B-97D9-E783F28764B2}.Release|x86.ActiveCfg = Release|Any CPU
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|Any CPU.ActiveCfg = Debug|x64
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|Any CPU.Build.0 = Debug|x64
- {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|x64.ActiveCfg = Debug|x64
- {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|x64.Build.0 = Debug|x64
- {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|x86.ActiveCfg = Debug|Any CPU
- {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Debug|x86.Build.0 = Debug|Any CPU
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|Any CPU.ActiveCfg = Release|x64
{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|Any CPU.Build.0 = Release|x64
- {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|x64.ActiveCfg = Release|x64
- {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|x64.Build.0 = Release|x64
- {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|x86.ActiveCfg = Release|Any CPU
- {B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}.Release|x86.Build.0 = Release|Any CPU
{55198DC3-A03D-408E-A8EB-2077780C8576}.Debug|Any CPU.ActiveCfg = Debug|x64
{55198DC3-A03D-408E-A8EB-2077780C8576}.Debug|Any CPU.Build.0 = Debug|x64
- {55198DC3-A03D-408E-A8EB-2077780C8576}.Debug|x64.ActiveCfg = Debug|x64
- {55198DC3-A03D-408E-A8EB-2077780C8576}.Debug|x64.Build.0 = Debug|x64
- {55198DC3-A03D-408E-A8EB-2077780C8576}.Debug|x86.ActiveCfg = Debug|x64
- {55198DC3-A03D-408E-A8EB-2077780C8576}.Debug|x86.Build.0 = Debug|x64
{55198DC3-A03D-408E-A8EB-2077780C8576}.Release|Any CPU.ActiveCfg = Release|x64
{55198DC3-A03D-408E-A8EB-2077780C8576}.Release|Any CPU.Build.0 = Release|x64
- {55198DC3-A03D-408E-A8EB-2077780C8576}.Release|x64.ActiveCfg = Release|x64
- {55198DC3-A03D-408E-A8EB-2077780C8576}.Release|x64.Build.0 = Release|x64
- {55198DC3-A03D-408E-A8EB-2077780C8576}.Release|x86.ActiveCfg = Release|x64
- {55198DC3-A03D-408E-A8EB-2077780C8576}.Release|x86.Build.0 = Release|x64
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|Any CPU.ActiveCfg = Debug|x64
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|Any CPU.Build.0 = Debug|x64
- {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|x64.ActiveCfg = Debug|x64
- {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|x64.Build.0 = Debug|x64
- {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|x86.ActiveCfg = Debug|Any CPU
- {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Debug|x86.Build.0 = Debug|Any CPU
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|Any CPU.ActiveCfg = Release|x64
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|Any CPU.Build.0 = Release|x64
- {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x64.ActiveCfg = Release|x64
- {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x64.Build.0 = Release|x64
- {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x86.ActiveCfg = Release|Any CPU
- {5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x86.Build.0 = Release|Any CPU
{8874326B-E755-4D13-90B4-59AB263A3E6B}.Debug|Any CPU.ActiveCfg = Debug|x64
{8874326B-E755-4D13-90B4-59AB263A3E6B}.Debug|Any CPU.Build.0 = Debug|x64
- {8874326B-E755-4D13-90B4-59AB263A3E6B}.Debug|x64.ActiveCfg = Debug|x64
- {8874326B-E755-4D13-90B4-59AB263A3E6B}.Debug|x64.Build.0 = Debug|x64
- {8874326B-E755-4D13-90B4-59AB263A3E6B}.Debug|x86.ActiveCfg = Debug|x64
- {8874326B-E755-4D13-90B4-59AB263A3E6B}.Debug|x86.Build.0 = Debug|x64
{8874326B-E755-4D13-90B4-59AB263A3E6B}.Release|Any CPU.ActiveCfg = Release|x64
{8874326B-E755-4D13-90B4-59AB263A3E6B}.Release|Any CPU.Build.0 = Release|x64
- {8874326B-E755-4D13-90B4-59AB263A3E6B}.Release|x64.ActiveCfg = Release|x64
- {8874326B-E755-4D13-90B4-59AB263A3E6B}.Release|x64.Build.0 = Release|x64
- {8874326B-E755-4D13-90B4-59AB263A3E6B}.Release|x86.ActiveCfg = Release|x64
- {8874326B-E755-4D13-90B4-59AB263A3E6B}.Release|x86.Build.0 = Release|x64
{C8004563-1806-4329-844F-0EF6274291FC}.Debug|Any CPU.ActiveCfg = Debug|x64
{C8004563-1806-4329-844F-0EF6274291FC}.Debug|Any CPU.Build.0 = Debug|x64
- {C8004563-1806-4329-844F-0EF6274291FC}.Debug|x64.ActiveCfg = Debug|x64
- {C8004563-1806-4329-844F-0EF6274291FC}.Debug|x64.Build.0 = Debug|x64
- {C8004563-1806-4329-844F-0EF6274291FC}.Debug|x86.ActiveCfg = Debug|Any CPU
- {C8004563-1806-4329-844F-0EF6274291FC}.Debug|x86.Build.0 = Debug|Any CPU
{C8004563-1806-4329-844F-0EF6274291FC}.Release|Any CPU.ActiveCfg = Release|x64
{C8004563-1806-4329-844F-0EF6274291FC}.Release|Any CPU.Build.0 = Release|x64
- {C8004563-1806-4329-844F-0EF6274291FC}.Release|x64.ActiveCfg = Release|x64
- {C8004563-1806-4329-844F-0EF6274291FC}.Release|x64.Build.0 = Release|x64
- {C8004563-1806-4329-844F-0EF6274291FC}.Release|x86.ActiveCfg = Release|Any CPU
- {C8004563-1806-4329-844F-0EF6274291FC}.Release|x86.Build.0 = Release|Any CPU
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|Any CPU.ActiveCfg = Debug|x64
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|Any CPU.Build.0 = Debug|x64
- {0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|x64.ActiveCfg = Debug|x64
- {0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|x64.Build.0 = Debug|x64
- {0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|x86.ActiveCfg = Debug|x64
- {0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|x86.Build.0 = Debug|x64
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|Any CPU.ActiveCfg = Release|x64
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|Any CPU.Build.0 = Release|x64
- {0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|x64.ActiveCfg = Release|x64
- {0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|x64.Build.0 = Release|x64
- {0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|x86.ActiveCfg = Release|x64
- {0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|x86.Build.0 = Release|x64
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|Any CPU.ActiveCfg = Debug|x64
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|Any CPU.Build.0 = Debug|x64
- {C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|x64.ActiveCfg = Debug|x64
- {C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|x64.Build.0 = Debug|x64
- {C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|x86.ActiveCfg = Debug|x64
- {C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Debug|x86.Build.0 = Debug|x64
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|Any CPU.ActiveCfg = Release|x64
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|Any CPU.Build.0 = Release|x64
- {C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|x64.ActiveCfg = Release|x64
- {C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|x64.Build.0 = Release|x64
- {C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|x86.ActiveCfg = Release|x64
- {C0E7E797-4FBF-4F46-BC57-463F3719BA7A}.Release|x86.Build.0 = Release|x64
{2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Debug|Any CPU.ActiveCfg = Debug|x64
{2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Debug|Any CPU.Build.0 = Debug|x64
- {2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Debug|x64.ActiveCfg = Debug|x64
- {2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Debug|x64.Build.0 = Debug|x64
- {2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Debug|x86.ActiveCfg = Debug|x64
- {2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Debug|x86.Build.0 = Debug|x64
{2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Release|Any CPU.ActiveCfg = Release|x64
{2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Release|Any CPU.Build.0 = Release|x64
- {2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Release|x64.ActiveCfg = Release|x64
- {2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Release|x64.Build.0 = Release|x64
- {2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Release|x86.ActiveCfg = Release|x64
- {2F7FF0A8-B619-4572-86C7-71E46FE22FB8}.Release|x86.Build.0 = Release|x64
{4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Debug|Any CPU.ActiveCfg = Debug|x64
{4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Debug|Any CPU.Build.0 = Debug|x64
- {4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Debug|x64.ActiveCfg = Debug|x64
- {4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Debug|x64.Build.0 = Debug|x64
- {4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Debug|x86.ActiveCfg = Debug|x64
- {4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Debug|x86.Build.0 = Debug|x64
{4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Release|Any CPU.ActiveCfg = Release|x64
{4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Release|Any CPU.Build.0 = Release|x64
- {4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Release|x64.ActiveCfg = Release|x64
- {4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Release|x64.Build.0 = Release|x64
- {4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Release|x86.ActiveCfg = Release|x64
- {4AFDB34A-7467-4D41-B067-53BC4101D9D0}.Release|x86.Build.0 = Release|x64
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Debug|x64.ActiveCfg = Debug|Any CPU
- {C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Debug|x64.Build.0 = Debug|Any CPU
- {C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Debug|x86.ActiveCfg = Debug|Any CPU
- {C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Debug|x86.Build.0 = Debug|Any CPU
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Release|Any CPU.Build.0 = Release|Any CPU
- {C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Release|x64.ActiveCfg = Release|Any CPU
- {C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Release|x64.Build.0 = Release|Any CPU
- {C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Release|x86.ActiveCfg = Release|Any CPU
- {C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Release|x86.Build.0 = Release|Any CPU
{05AB2F46-268B-4915-806F-DDF813E2D59D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{05AB2F46-268B-4915-806F-DDF813E2D59D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {05AB2F46-268B-4915-806F-DDF813E2D59D}.Debug|x64.ActiveCfg = Debug|Any CPU
- {05AB2F46-268B-4915-806F-DDF813E2D59D}.Debug|x64.Build.0 = Debug|Any CPU
- {05AB2F46-268B-4915-806F-DDF813E2D59D}.Debug|x86.ActiveCfg = Debug|Any CPU
- {05AB2F46-268B-4915-806F-DDF813E2D59D}.Debug|x86.Build.0 = Debug|Any CPU
{05AB2F46-268B-4915-806F-DDF813E2D59D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{05AB2F46-268B-4915-806F-DDF813E2D59D}.Release|Any CPU.Build.0 = Release|Any CPU
- {05AB2F46-268B-4915-806F-DDF813E2D59D}.Release|x64.ActiveCfg = Release|Any CPU
- {05AB2F46-268B-4915-806F-DDF813E2D59D}.Release|x64.Build.0 = Release|Any CPU
- {05AB2F46-268B-4915-806F-DDF813E2D59D}.Release|x86.ActiveCfg = Release|Any CPU
- {05AB2F46-268B-4915-806F-DDF813E2D59D}.Release|x86.Build.0 = Release|Any CPU
{317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|Any CPU.ActiveCfg = Debug|x64
{317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|Any CPU.Build.0 = Debug|x64
- {317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|x64.ActiveCfg = Debug|x64
- {317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|x64.Build.0 = Debug|x64
- {317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|x86.ActiveCfg = Debug|x64
- {317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|x86.Build.0 = Debug|x64
{317A264C-920B-44A1-8A34-F3A6827B0705}.Release|Any CPU.ActiveCfg = Release|x64
{317A264C-920B-44A1-8A34-F3A6827B0705}.Release|Any CPU.Build.0 = Release|x64
- {317A264C-920B-44A1-8A34-F3A6827B0705}.Release|x64.ActiveCfg = Release|x64
- {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
{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
diff --git a/Dalamud/Configuration/Internal/DalamudConfiguration.cs b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
index 66c2745c5..85a9507c9 100644
--- a/Dalamud/Configuration/Internal/DalamudConfiguration.cs
+++ b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
@@ -5,6 +5,7 @@ using System.IO;
using System.Linq;
using Dalamud.Game.Text;
+using Dalamud.Interface.FontIdentifier;
using Dalamud.Interface.Internal.Windows.PluginInstaller;
using Dalamud.Interface.Style;
using Dalamud.IoC.Internal;
@@ -145,7 +146,13 @@ internal sealed class DalamudConfiguration : IServiceType, IDisposable
///
/// Gets or sets a value indicating whether to use AXIS fonts from the game.
///
- public bool UseAxisFontsFromGame { get; set; } = false;
+ [Obsolete($"See {nameof(DefaultFontSpec)}")]
+ public bool UseAxisFontsFromGame { get; set; } = true;
+
+ ///
+ /// Gets or sets the default font spec.
+ ///
+ public IFontSpec? DefaultFontSpec { get; set; }
///
/// Gets or sets the gamma value to apply for Dalamud fonts. Do not use.
@@ -208,6 +215,11 @@ internal sealed class DalamudConfiguration : IServiceType, IDisposable
///
public bool LogOpenAtStartup { get; set; }
+ ///
+ /// Gets or sets the number of lines to keep for the Dalamud Console window.
+ ///
+ public int LogLinesLimit { get; set; } = 10000;
+
///
/// Gets or sets a value indicating whether or not the dev bar should open at startup.
///
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index 434e6f868..f6ac5b151 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -8,7 +8,7 @@
- 9.0.0.17
+ 9.0.0.21
XIV Launcher addon framework
$(DalamudVersion)
$(DalamudVersion)
@@ -68,7 +68,7 @@
-
+
diff --git a/Dalamud/Game/Config/GameConfig.cs b/Dalamud/Game/Config/GameConfig.cs
index b82d64f24..162df9417 100644
--- a/Dalamud/Game/Config/GameConfig.cs
+++ b/Dalamud/Game/Config/GameConfig.cs
@@ -1,4 +1,6 @@
-using Dalamud.Hooking;
+using System.Threading.Tasks;
+
+using Dalamud.Hooking;
using Dalamud.IoC;
using Dalamud.IoC.Internal;
using Dalamud.Plugin.Services;
@@ -15,6 +17,11 @@ namespace Dalamud.Game.Config;
[ServiceManager.BlockingEarlyLoadedService]
internal sealed class GameConfig : IServiceType, IGameConfig, IDisposable
{
+ private readonly TaskCompletionSource tcsInitialization = new();
+ private readonly TaskCompletionSource tcsSystem = new();
+ private readonly TaskCompletionSource tcsUiConfig = new();
+ private readonly TaskCompletionSource tcsUiControl = new();
+
private readonly GameConfigAddressResolver address = new();
private Hook? configChangeHook;
@@ -23,16 +30,32 @@ internal sealed class GameConfig : IServiceType, IGameConfig, IDisposable
{
framework.RunOnTick(() =>
{
- Log.Verbose("[GameConfig] Initializing");
- var csFramework = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework.Instance();
- var commonConfig = &csFramework->SystemConfig.CommonSystemConfig;
- this.System = new GameConfigSection("System", framework, &commonConfig->ConfigBase);
- this.UiConfig = new GameConfigSection("UiConfig", framework, &commonConfig->UiConfig);
- this.UiControl = new GameConfigSection("UiControl", framework, () => this.UiConfig.TryGetBool("PadMode", out var padMode) && padMode ? &commonConfig->UiControlGamepadConfig : &commonConfig->UiControlConfig);
-
- this.address.Setup(sigScanner);
- this.configChangeHook = Hook.FromAddress(this.address.ConfigChangeAddress, this.OnConfigChanged);
- this.configChangeHook.Enable();
+ try
+ {
+ Log.Verbose("[GameConfig] Initializing");
+ var csFramework = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework.Instance();
+ var commonConfig = &csFramework->SystemConfig.CommonSystemConfig;
+ this.tcsSystem.SetResult(new("System", framework, &commonConfig->ConfigBase));
+ this.tcsUiConfig.SetResult(new("UiConfig", framework, &commonConfig->UiConfig));
+ this.tcsUiControl.SetResult(
+ new(
+ "UiControl",
+ framework,
+ () => this.UiConfig.TryGetBool("PadMode", out var padMode) && padMode
+ ? &commonConfig->UiControlGamepadConfig
+ : &commonConfig->UiControlConfig));
+
+ this.address.Setup(sigScanner);
+ this.configChangeHook = Hook.FromAddress(
+ this.address.ConfigChangeAddress,
+ this.OnConfigChanged);
+ this.configChangeHook.Enable();
+ this.tcsInitialization.SetResult();
+ }
+ catch (Exception ex)
+ {
+ this.tcsInitialization.SetExceptionIfIncomplete(ex);
+ }
});
}
@@ -58,14 +81,19 @@ internal sealed class GameConfig : IServiceType, IGameConfig, IDisposable
public event EventHandler? UiControlChanged;
#pragma warning restore 67
- ///
- public GameConfigSection System { get; private set; }
+ ///
+ /// Gets a task representing the initialization state of this class.
+ ///
+ public Task InitializationTask => this.tcsInitialization.Task;
///
- public GameConfigSection UiConfig { get; private set; }
+ public GameConfigSection System => this.tcsSystem.Task.Result;
///
- public GameConfigSection UiControl { get; private set; }
+ public GameConfigSection UiConfig => this.tcsUiConfig.Task.Result;
+
+ ///
+ public GameConfigSection UiControl => this.tcsUiControl.Task.Result;
///
public bool TryGet(SystemConfigOption option, out bool value) => this.System.TryGet(option.GetName(), out value);
@@ -169,6 +197,11 @@ internal sealed class GameConfig : IServiceType, IGameConfig, IDisposable
///
void IDisposable.Dispose()
{
+ var ode = new ObjectDisposedException(nameof(GameConfig));
+ this.tcsInitialization.SetExceptionIfIncomplete(ode);
+ this.tcsSystem.SetExceptionIfIncomplete(ode);
+ this.tcsUiConfig.SetExceptionIfIncomplete(ode);
+ this.tcsUiControl.SetExceptionIfIncomplete(ode);
this.configChangeHook?.Disable();
this.configChangeHook?.Dispose();
}
@@ -220,15 +253,24 @@ internal class GameConfigPluginScoped : IDisposable, IServiceType, IGameConfig
[ServiceManager.ServiceDependency]
private readonly GameConfig gameConfigService = Service.Get();
+ private readonly Task initializationTask;
+
///
/// Initializes a new instance of the class.
///
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;
+ this.initializationTask = this.gameConfigService.InitializationTask.ContinueWith(
+ r =>
+ {
+ if (!r.IsCompletedSuccessfully)
+ return r;
+ this.gameConfigService.System.Changed += this.SystemConfigChangedForward;
+ this.gameConfigService.UiConfig.Changed += this.UiConfigConfigChangedForward;
+ this.gameConfigService.UiControl.Changed += this.UiControlConfigChangedForward;
+ return Task.CompletedTask;
+ }).Unwrap();
}
///
@@ -256,9 +298,15 @@ internal class GameConfigPluginScoped : IDisposable, IServiceType, IGameConfig
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.initializationTask.ContinueWith(
+ r =>
+ {
+ if (!r.IsCompletedSuccessfully)
+ return;
+ this.gameConfigService.System.Changed -= this.SystemConfigChangedForward;
+ this.gameConfigService.UiConfig.Changed -= this.UiConfigConfigChangedForward;
+ this.gameConfigService.UiControl.Changed -= this.UiControlConfigChangedForward;
+ });
this.Changed = null;
this.SystemChanged = null;
diff --git a/Dalamud/Game/Gui/ContextMenu/ContextMenu.cs b/Dalamud/Game/Gui/ContextMenu/ContextMenu.cs
new file mode 100644
index 000000000..65c9b2760
--- /dev/null
+++ b/Dalamud/Game/Gui/ContextMenu/ContextMenu.cs
@@ -0,0 +1,560 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+using Dalamud.Game.Text;
+using Dalamud.Game.Text.SeStringHandling;
+using Dalamud.Hooking;
+using Dalamud.IoC;
+using Dalamud.IoC.Internal;
+using Dalamud.Logging.Internal;
+using Dalamud.Memory;
+using Dalamud.Plugin.Services;
+using Dalamud.Utility;
+
+using FFXIVClientStructs.FFXIV.Client.System.Memory;
+using FFXIVClientStructs.FFXIV.Client.UI;
+using FFXIVClientStructs.FFXIV.Client.UI.Agent;
+using FFXIVClientStructs.FFXIV.Component.GUI;
+using FFXIVClientStructs.Interop;
+
+using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType;
+
+namespace Dalamud.Game.Gui.ContextMenu;
+
+///
+/// This class handles interacting with the game's (right-click) context menu.
+///
+[InterfaceVersion("1.0")]
+[ServiceManager.EarlyLoadedService]
+internal sealed unsafe class ContextMenu : IDisposable, IServiceType, IContextMenu
+{
+ private static readonly ModuleLog Log = new("ContextMenu");
+
+ private readonly Hook raptureAtkModuleOpenAddonByAgentHook;
+ private readonly Hook addonContextMenuOnMenuSelectedHook;
+ private readonly RaptureAtkModuleOpenAddonDelegate raptureAtkModuleOpenAddon;
+
+ [ServiceManager.ServiceConstructor]
+ private ContextMenu()
+ {
+ this.raptureAtkModuleOpenAddonByAgentHook = Hook.FromAddress((nint)RaptureAtkModule.Addresses.OpenAddonByAgent.Value, this.RaptureAtkModuleOpenAddonByAgentDetour);
+ this.addonContextMenuOnMenuSelectedHook = Hook.FromAddress((nint)AddonContextMenu.StaticVTable.OnMenuSelected, this.AddonContextMenuOnMenuSelectedDetour);
+ this.raptureAtkModuleOpenAddon = Marshal.GetDelegateForFunctionPointer((nint)RaptureAtkModule.Addresses.OpenAddon.Value);
+
+ this.raptureAtkModuleOpenAddonByAgentHook.Enable();
+ this.addonContextMenuOnMenuSelectedHook.Enable();
+ }
+
+ private unsafe delegate ushort RaptureAtkModuleOpenAddonByAgentDelegate(RaptureAtkModule* module, byte* addonName, AtkUnitBase* addon, int valueCount, AtkValue* values, AgentInterface* agent, nint a7, ushort parentAddonId);
+
+ private unsafe delegate bool AddonContextMenuOnMenuSelectedDelegate(AddonContextMenu* addon, int selectedIdx, byte a3);
+
+ private unsafe delegate ushort RaptureAtkModuleOpenAddonDelegate(RaptureAtkModule* a1, uint addonNameId, uint valueCount, AtkValue* values, AgentInterface* parentAgent, ulong unk, ushort parentAddonId, int unk2);
+
+ ///
+ public event IContextMenu.OnMenuOpenedDelegate OnMenuOpened;
+
+ private Dictionary> MenuItems { get; } = new();
+
+ private object MenuItemsLock { get; } = new();
+
+ private AgentInterface* SelectedAgent { get; set; }
+
+ private ContextMenuType? SelectedMenuType { get; set; }
+
+ private List