From 08cd003ee768cc891526e10a03be6ae2fd5f0664 Mon Sep 17 00:00:00 2001 From: Koenari Date: Mon, 24 Oct 2022 13:16:01 +0200 Subject: [PATCH 01/51] feat: adapt to CheapLoc's new function signature --- Dalamud/Localization.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dalamud/Localization.cs b/Dalamud/Localization.cs index a050b71a0..51febc0e3 100644 --- a/Dalamud/Localization.cs +++ b/Dalamud/Localization.cs @@ -140,9 +140,10 @@ namespace Dalamud /// /// Saves localizable JSON data in the current working directory for the provided assembly. /// - public void ExportLocalizable() + /// If set to true, this ignores malformed Localize functions instead of failing. + public void ExportLocalizable(bool ignoreInvalidFunctions = false) { - Loc.ExportLocalizableForAssembly(this.assembly); + Loc.ExportLocalizableForAssembly(this.assembly, ignoreInvalidFunctions); } private string ReadLocData(string langCode) From 05e3330789415f01c433b7c54f4593b595351084 Mon Sep 17 00:00:00 2001 From: goat Date: Wed, 7 Dec 2022 22:59:44 +0100 Subject: [PATCH 02/51] chore: upgrade all projects to .NET 7 --- Dalamud.CorePlugin/Dalamud.CorePlugin.csproj | 2 +- Dalamud.Injector/Dalamud.Injector.csproj | 2 +- Dalamud.Test/Dalamud.Test.csproj | 2 +- Dalamud/Dalamud.csproj | 10 +++++----- Dalamud/Interface/Internal/DalamudInterface.cs | 1 + 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj b/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj index 8f184383c..05d4f570d 100644 --- a/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj +++ b/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj @@ -1,7 +1,7 @@ Dalamud.CorePlugin - net6.0-windows + net7.0-windows x64 10.0 true diff --git a/Dalamud.Injector/Dalamud.Injector.csproj b/Dalamud.Injector/Dalamud.Injector.csproj index f7da123fe..88948f6de 100644 --- a/Dalamud.Injector/Dalamud.Injector.csproj +++ b/Dalamud.Injector/Dalamud.Injector.csproj @@ -1,7 +1,7 @@ - net6.0 + net7.0 win-x64 x64 x64;AnyCPU diff --git a/Dalamud.Test/Dalamud.Test.csproj b/Dalamud.Test/Dalamud.Test.csproj index 143c3fc75..8f4ccf0dd 100644 --- a/Dalamud.Test/Dalamud.Test.csproj +++ b/Dalamud.Test/Dalamud.Test.csproj @@ -1,7 +1,7 @@ - net6.0-windows + net7.0-windows win-x64 x64 x64;AnyCPU diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index 579807ab2..43cde17b9 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -1,7 +1,7 @@ - net6.0-windows + net7.0-windows x64 x64;AnyCPU 10.0 @@ -80,10 +80,10 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs index 078bbd661..9c55b6452 100644 --- a/Dalamud/Interface/Internal/DalamudInterface.cs +++ b/Dalamud/Interface/Internal/DalamudInterface.cs @@ -671,6 +671,7 @@ internal class DalamudInterface : IDisposable, IServiceType ImGui.MenuItem(Util.AssemblyVersion, false); ImGui.MenuItem(startInfo.GameVersion.ToString(), false); ImGui.MenuItem($"D: {Util.GetGitHash()} CS: {Util.GetGitHashClientStructs()}", false); + ImGui.MenuItem($"CLR: {Environment.Version}", false); ImGui.EndMenu(); } From 2f4243b6d45202527b1970c794f8eb9b05897557 Mon Sep 17 00:00:00 2001 From: goat Date: Wed, 7 Dec 2022 23:08:25 +0100 Subject: [PATCH 03/51] deps: bump nuke, fix bad System.Drawing.Common version --- Dalamud/Dalamud.csproj | 2 +- build/build.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index 43cde17b9..4a6064295 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -81,7 +81,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/build/build.csproj b/build/build.csproj index 270ea0a0f..b5ab6f8bf 100644 --- a/build/build.csproj +++ b/build/build.csproj @@ -10,6 +10,6 @@ 1 - + From 82eebca9a920ca68ce653ae643809a0beb3dcc57 Mon Sep 17 00:00:00 2001 From: goat Date: Wed, 7 Dec 2022 23:12:49 +0100 Subject: [PATCH 04/51] chore: bump nuke build project to .net 7 --- build/build.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.csproj b/build/build.csproj index b5ab6f8bf..46d416199 100644 --- a/build/build.csproj +++ b/build/build.csproj @@ -1,7 +1,7 @@  Exe - net5.0 + net7.0 disable IDE0002;IDE0051;IDE1006;CS0649;CS0169 From c4a4b873d3aff391e680703fb336140408a6c215 Mon Sep 17 00:00:00 2001 From: goat Date: Wed, 7 Dec 2022 23:29:31 +0100 Subject: [PATCH 05/51] ci: maybe try to update powershell before deploy? --- .github/workflows/main.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 598602be8..8d87e0f6c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -56,6 +56,12 @@ jobs: run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" id: extract_branch + # GitHub only ships the LTS, which is stuck on .NET 6 + - name: Install PowerShell latest + shell: pwsh + run: | + Invoke-Expression "& { $(Invoke-RestMethod https://aka.ms/install-powershell.ps1) } -UseMSI -Quiet" + - name: Generate dalamud-distrib version file shell: pwsh env: From 2f4efe4e50089fe00f60c05063259ee74f10433d Mon Sep 17 00:00:00 2001 From: goat Date: Sat, 10 Dec 2022 11:30:11 +0100 Subject: [PATCH 06/51] chore: output assembly ver for builds --- .github/workflows/main.yml | 10 +--------- Dalamud/Dalamud.csproj | 7 +++++++ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8d87e0f6c..7631e8242 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -56,12 +56,6 @@ jobs: run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" id: extract_branch - # GitHub only ships the LTS, which is stuck on .NET 6 - - name: Install PowerShell latest - shell: pwsh - run: | - Invoke-Expression "& { $(Invoke-RestMethod https://aka.ms/install-powershell.ps1) } -UseMSI -Quiet" - - name: Generate dalamud-distrib version file shell: pwsh env: @@ -75,9 +69,7 @@ jobs: $branchName = "stg" } - $dllBytes = [System.IO.File]::ReadAllBytes("$(Get-Location)\scratch\Dalamud.dll") - $assembly = [System.Reflection.Assembly]::Load($dllBytes) - $newVersion = $assembly.GetCustomAttributes([System.Reflection.AssemblyMetadataAttribute]) | Where { $_.GetType() -eq [System.Reflection.AssemblyMetadataAttribute] } | Select -First 1 | Select -ExpandProperty "Value" + $newVersion = [System.IO.File]::ReadAllText("$(Get-Location)\scratch\TEMP_assver.txt") Remove-Item -Force -Recurse .\scratch if (Test-Path -Path $branchName) { diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index 4a6064295..499128ea9 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -109,6 +109,13 @@ + + + + $(OutputPath)TEMP_assver.txt + + + From 1dd0d60e26a812144b981668f88e68a7df4b160a Mon Sep 17 00:00:00 2001 From: goat Date: Sat, 10 Dec 2022 11:48:54 +0100 Subject: [PATCH 07/51] actually, use the git hash for this for now --- Dalamud/Dalamud.csproj | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index 499128ea9..a7bba8340 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -109,23 +109,20 @@ - - - - $(OutputPath)TEMP_assver.txt - - - $(IntermediateOutputPath)gitver $(IntermediateOutputPath)csver + $(OutputPath)TEMP_gitver.txt + + + From e0585a2feb7cb5420da40cff7a74c9b5dc5091fa Mon Sep 17 00:00:00 2001 From: goat Date: Sat, 10 Dec 2022 12:00:26 +0100 Subject: [PATCH 08/51] chore: don't run git commands for debug builds --- Dalamud/Dalamud.csproj | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index a7bba8340..c861913b0 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -110,7 +110,7 @@ - + $(IntermediateOutputPath)gitver @@ -136,7 +136,7 @@ @(GitVersionClientStructs) - + $(IntermediateOutputPath)CustomAssemblyInfo.cs @@ -159,4 +159,30 @@ + + + + + + $(IntermediateOutputPath)CustomAssemblyInfo.cs + Local build at $([System.DateTime]::Now.ToString(yyyyMMdd-hhmmss)) + + + + + + + + + <_Parameter1>GitHash + <_Parameter2>$(LocalBuildText) + + + <_Parameter1>GitHashClientStructs + <_Parameter2>$(LocalBuildText) + + + + + From 2542ec7bcd6d880deacf6912089f094e8bc27226 Mon Sep 17 00:00:00 2001 From: goat Date: Sat, 10 Dec 2022 12:11:02 +0100 Subject: [PATCH 09/51] throw around some unchecked because warnings --- Dalamud/Memory/MemoryHelper.cs | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/Dalamud/Memory/MemoryHelper.cs b/Dalamud/Memory/MemoryHelper.cs index f97461e66..5b640f64c 100644 --- a/Dalamud/Memory/MemoryHelper.cs +++ b/Dalamud/Memory/MemoryHelper.cs @@ -583,15 +583,18 @@ public static unsafe class MemoryHelper /// The read in bytes. public static void ReadProcessMemory(IntPtr memoryAddress, ref byte[] value) { - var length = value.Length; - var result = NativeFunctions.ReadProcessMemory((IntPtr)0xFFFFFFFF, memoryAddress, value, length, out _); + unchecked + { + var length = value.Length; + var result = NativeFunctions.ReadProcessMemory((IntPtr)0xFFFFFFFF, memoryAddress, value, length, out _); - if (!result) - throw new MemoryReadException($"Unable to read memory at 0x{memoryAddress.ToInt64():X} of length {length} (result={result})"); + if (!result) + throw new MemoryReadException($"Unable to read memory at 0x{memoryAddress.ToInt64():X} of length {length} (result={result})"); - var last = Marshal.GetLastWin32Error(); - if (last > 0) - throw new MemoryReadException($"Unable to read memory at 0x{memoryAddress.ToInt64():X} of length {length} (error={last})"); + var last = Marshal.GetLastWin32Error(); + if (last > 0) + throw new MemoryReadException($"Unable to read memory at 0x{memoryAddress.ToInt64():X} of length {length} (error={last})"); + } } /// @@ -602,15 +605,18 @@ public static unsafe class MemoryHelper /// The bytes to write to memoryAddress. public static void WriteProcessMemory(IntPtr memoryAddress, byte[] data) { - var length = data.Length; - var result = NativeFunctions.WriteProcessMemory((IntPtr)0xFFFFFFFF, memoryAddress, data, length, out _); + unchecked + { + var length = data.Length; + var result = NativeFunctions.WriteProcessMemory((IntPtr)0xFFFFFFFF, memoryAddress, data, length, out _); - if (!result) - throw new MemoryWriteException($"Unable to write memory at 0x{memoryAddress.ToInt64():X} of length {length} (result={result})"); + if (!result) + throw new MemoryWriteException($"Unable to write memory at 0x{memoryAddress.ToInt64():X} of length {length} (result={result})"); - var last = Marshal.GetLastWin32Error(); - if (last > 0) - throw new MemoryWriteException($"Unable to write memory at 0x{memoryAddress.ToInt64():X} of length {length} (error={last})"); + var last = Marshal.GetLastWin32Error(); + if (last > 0) + throw new MemoryWriteException($"Unable to write memory at 0x{memoryAddress.ToInt64():X} of length {length} (error={last})"); + } } #endregion From 67f35397da5163c91dc02b21f55f40203f1dd4f6 Mon Sep 17 00:00:00 2001 From: goat Date: Sat, 10 Dec 2022 12:29:39 +0100 Subject: [PATCH 10/51] switch to .NET 7 SDK globally --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 9e5e1fd1d..7cd6a1f4f 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.0", + "version": "7.0.0", "rollForward": "latestMajor", "allowPrerelease": true } From 80afbf9f45a6bca05569d24f9eec709fab152c4a Mon Sep 17 00:00:00 2001 From: goat Date: Sat, 10 Dec 2022 12:30:54 +0100 Subject: [PATCH 11/51] fix deploy again --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7631e8242..cf708326b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -69,7 +69,7 @@ jobs: $branchName = "stg" } - $newVersion = [System.IO.File]::ReadAllText("$(Get-Location)\scratch\TEMP_assver.txt") + $newVersion = [System.IO.File]::ReadAllText("$(Get-Location)\scratch\TEMP_gitver.txt") Remove-Item -Force -Recurse .\scratch if (Test-Path -Path $branchName) { From 407b03ea57494a6d35e0fdfc726afcb42d89e3e7 Mon Sep 17 00:00:00 2001 From: goat Date: Sat, 10 Dec 2022 12:31:06 +0100 Subject: [PATCH 12/51] deps: bump CS --- Dalamud/Game/ClientState/Party/PartyList.cs | 2 +- lib/FFXIVClientStructs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dalamud/Game/ClientState/Party/PartyList.cs b/Dalamud/Game/ClientState/Party/PartyList.cs index 5312be67c..80fe7d41f 100644 --- a/Dalamud/Game/ClientState/Party/PartyList.cs +++ b/Dalamud/Game/ClientState/Party/PartyList.cs @@ -46,7 +46,7 @@ public sealed unsafe partial class PartyList : IServiceType /// /// Gets a value indicating whether this group is an alliance. /// - public bool IsAlliance => this.GroupManagerStruct->IsAlliance; + public bool IsAlliance => this.GroupManagerStruct->AllianceFlags > 0; /// /// Gets the address of the Group Manager. diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index 9cb2eb338..aa8cf2754 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit 9cb2eb33826f62f7e3525e1f6ca08a974b35c76b +Subproject commit aa8cf2754333fcc98b3e10c0fc9461e4de22a49d From 777d79826594c5e16b1f6db11c995329347e1c4a Mon Sep 17 00:00:00 2001 From: goat Date: Sat, 10 Dec 2022 12:36:04 +0100 Subject: [PATCH 13/51] remove deprecated Nuke attribute --- build/DalamudBuild.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/build/DalamudBuild.cs b/build/DalamudBuild.cs index d46e4b562..c8c118c31 100644 --- a/build/DalamudBuild.cs +++ b/build/DalamudBuild.cs @@ -8,7 +8,6 @@ using Nuke.Common.ProjectModel; using Nuke.Common.Tools.DotNet; using Nuke.Common.Tools.MSBuild; -[CheckBuildProjectConfigurations] [UnsetVisualStudioEnvironmentVariables] public class DalamudBuild : NukeBuild { From a38716d5baa8bb026dbe9f3c5b81792240b79af4 Mon Sep 17 00:00:00 2001 From: goat Date: Sat, 10 Dec 2022 12:54:26 +0100 Subject: [PATCH 14/51] update build.schema.json --- .nuke/build.schema.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json index 27cfe4d84..c19388eea 100644 --- a/.nuke/build.schema.json +++ b/.nuke/build.schema.json @@ -29,6 +29,7 @@ "AppVeyor", "AzurePipelines", "Bamboo", + "Bitbucket", "Bitrise", "GitHubActions", "GitLab", From 4f74b7401a400aa9bdd1484ccdff8ffc09d78926 Mon Sep 17 00:00:00 2001 From: goat Date: Sat, 10 Dec 2022 13:17:56 +0100 Subject: [PATCH 15/51] deps: bump Newtonsoft.JSON to 13.0.2 --- Dalamud.CorePlugin/Dalamud.CorePlugin.csproj | 2 +- Dalamud.Injector/Dalamud.Injector.csproj | 2 +- Dalamud/Dalamud.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj b/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj index 05d4f570d..d93f4bf25 100644 --- a/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj +++ b/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj @@ -29,7 +29,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Dalamud.Injector/Dalamud.Injector.csproj b/Dalamud.Injector/Dalamud.Injector.csproj index 88948f6de..ea9e4f0a3 100644 --- a/Dalamud.Injector/Dalamud.Injector.csproj +++ b/Dalamud.Injector/Dalamud.Injector.csproj @@ -62,7 +62,7 @@ - + diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index c861913b0..66487bc91 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -71,7 +71,7 @@ - + From d3797e2ff6e209131c4d22ad5d1165d1a8e965a6 Mon Sep 17 00:00:00 2001 From: goat Date: Sat, 10 Dec 2022 17:21:22 +0100 Subject: [PATCH 16/51] write version files without newlines --- Dalamud/Dalamud.csproj | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index 66487bc91..1c1da09fd 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -112,29 +112,25 @@ - - $(IntermediateOutputPath)gitver - $(IntermediateOutputPath)csver $(OutputPath)TEMP_gitver.txt - - - - - - - - - - - - + + + + + + + + - @(GitVersion) - @(GitVersionClientStructs) + $([System.Text.RegularExpressions.Regex]::Replace($(DalamudGitDescribeOutput), @"\t|\n|\r", "")) + $([System.Text.RegularExpressions.Regex]::Replace($(ClientStructsGitDescribeOutput), @"\t|\n|\r", "")) + + + From 71bcbde13109fc37fd2e11246f89e5fd147c20bf Mon Sep 17 00:00:00 2001 From: goat Date: Sat, 10 Dec 2022 18:53:54 +0100 Subject: [PATCH 17/51] more logging for wine fixes --- Dalamud.Injector.Boot/main.cpp | 1 + lib/CoreCLR/boot.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Dalamud.Injector.Boot/main.cpp b/Dalamud.Injector.Boot/main.cpp index ee939968d..074dbc4b2 100644 --- a/Dalamud.Injector.Boot/main.cpp +++ b/Dalamud.Injector.Boot/main.cpp @@ -9,6 +9,7 @@ int wmain(int argc, wchar_t** argv) { + logging::start_file_logging("dalamud.injector.boot.log", true); logging::I("Dalamud Injector, (c) 2021 XIVLauncher Contributors"); logging::I("Built at : " __DATE__ "@" __TIME__); diff --git a/lib/CoreCLR/boot.cpp b/lib/CoreCLR/boot.cpp index d2ee58112..e332650cc 100644 --- a/lib/CoreCLR/boot.cpp +++ b/lib/CoreCLR/boot.cpp @@ -126,7 +126,7 @@ int InitializeClrAndGetEntryPoint( // =========================================================================== // - logging::I("Loading module..."); + logging::I("Loading module from {}...", module_path.c_str()); if ((result = g_clr->load_assembly_and_get_function_pointer( module_path.c_str(), entrypoint_assembly_name.c_str(), From f6c395809b294a85fa7eddf0749e65cad1a3801d Mon Sep 17 00:00:00 2001 From: goat Date: Sat, 10 Dec 2022 19:19:19 +0100 Subject: [PATCH 18/51] don't log to file --- Dalamud.Injector.Boot/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud.Injector.Boot/main.cpp b/Dalamud.Injector.Boot/main.cpp index 074dbc4b2..741505d08 100644 --- a/Dalamud.Injector.Boot/main.cpp +++ b/Dalamud.Injector.Boot/main.cpp @@ -9,7 +9,7 @@ int wmain(int argc, wchar_t** argv) { - logging::start_file_logging("dalamud.injector.boot.log", true); + //logging::start_file_logging("dalamud.injector.boot.log", true); logging::I("Dalamud Injector, (c) 2021 XIVLauncher Contributors"); logging::I("Built at : " __DATE__ "@" __TIME__); From f0c254f8e2d1f4ddfb4329e376894c5aae51042c Mon Sep 17 00:00:00 2001 From: goat Date: Sat, 10 Dec 2022 22:14:52 +0100 Subject: [PATCH 19/51] fix version attributes, again --- Dalamud/Dalamud.csproj | 52 ++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index 1c1da09fd..9eb0a7c7f 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -110,11 +110,12 @@ - - - $(OutputPath)TEMP_gitver.txt - - + + + $(OutputPath)TEMP_gitver.txt + + + @@ -132,7 +133,20 @@ - + + + + + Local build at $([System.DateTime]::Now.ToString(yyyyMMdd-hhmmss)) + $(LocalBuildText) + ??? + + + + + + + $(IntermediateOutputPath)CustomAssemblyInfo.cs @@ -155,30 +169,4 @@ - - - - - - $(IntermediateOutputPath)CustomAssemblyInfo.cs - Local build at $([System.DateTime]::Now.ToString(yyyyMMdd-hhmmss)) - - - - - - - - - <_Parameter1>GitHash - <_Parameter2>$(LocalBuildText) - - - <_Parameter1>GitHashClientStructs - <_Parameter2>$(LocalBuildText) - - - - - From f78c5157c8fe5c8a9c03c496de44655f4749cf38 Mon Sep 17 00:00:00 2001 From: goat Date: Wed, 14 Dec 2022 21:57:21 +0100 Subject: [PATCH 20/51] feat: defer texturewrap dispose until the end of the frame --- Dalamud/Dalamud.csproj | 4 +- .../Interface/Internal/DalamudTextureWrap.cs | 54 +++++++++++++++++++ .../Interface/Internal/InterfaceManager.cs | 27 ++++++++-- 3 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 Dalamud/Interface/Internal/DalamudTextureWrap.cs diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index 9eb0a7c7f..5e406acdb 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -131,7 +131,7 @@ - + @@ -143,7 +143,7 @@ - + diff --git a/Dalamud/Interface/Internal/DalamudTextureWrap.cs b/Dalamud/Interface/Internal/DalamudTextureWrap.cs new file mode 100644 index 000000000..346b7cd24 --- /dev/null +++ b/Dalamud/Interface/Internal/DalamudTextureWrap.cs @@ -0,0 +1,54 @@ +using System; + +using ImGuiScene; + +namespace Dalamud.Interface.Internal; + +/// +/// Safety harness for ImGuiScene textures that will defer destruction until +/// the end of the frame. +/// +public class DalamudTextureWrap : TextureWrap +{ + private readonly TextureWrap wrappedWrap; + + /// + /// Initializes a new instance of the class. + /// + /// The texture wrap to wrap. + internal DalamudTextureWrap(TextureWrap wrappingWrap) + { + this.wrappedWrap = wrappingWrap; + } + + /// + /// Gets the ImGui handle of the texture. + /// + public IntPtr ImGuiHandle => this.wrappedWrap.ImGuiHandle; + + /// + /// Gets the width of the texture. + /// + public int Width => this.wrappedWrap.Width; + + /// + /// Gets the height of the texture. + /// + public int Height => this.wrappedWrap.Height; + + /// + /// Queue the texture to be disposed once the frame ends. + /// + public void Dispose() + { + Service.Get().EnqueueDeferredDispose(this); + } + + /// + /// Actually dispose the wrapped texture. + /// + internal void RealDispose() + { + this.wrappedWrap.Dispose(); + } +} diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs index 5e6da15c1..41bd8e9c7 100644 --- a/Dalamud/Interface/Internal/InterfaceManager.cs +++ b/Dalamud/Interface/Internal/InterfaceManager.cs @@ -56,6 +56,8 @@ internal class InterfaceManager : IDisposable, IServiceType private readonly HashSet glyphRequests = new(); private readonly Dictionary loadedFontInfo = new(); + private readonly List deferredDisposeTextures = new(); + [ServiceManager.ServiceDependency] private readonly Framework framework = Service.Get(); @@ -242,7 +244,8 @@ internal class InterfaceManager : IDisposable, IServiceType try { - return this.scene?.LoadImage(filePath) ?? null; + var wrap = this.scene?.LoadImage(filePath); + return wrap != null ? new DalamudTextureWrap(wrap) : null; } catch (Exception ex) { @@ -264,7 +267,8 @@ internal class InterfaceManager : IDisposable, IServiceType try { - return this.scene?.LoadImage(imageData) ?? null; + var wrap = this.scene?.LoadImage(imageData); + return wrap != null ? new DalamudTextureWrap(wrap) : null; } catch (Exception ex) { @@ -289,7 +293,8 @@ internal class InterfaceManager : IDisposable, IServiceType try { - return this.scene?.LoadImageRaw(imageData, width, height, numChannels) ?? null; + var wrap = this.scene?.LoadImageRaw(imageData, width, height, numChannels); + return wrap != null ? new DalamudTextureWrap(wrap) : null; } catch (Exception ex) { @@ -395,6 +400,15 @@ internal class InterfaceManager : IDisposable, IServiceType return this.NewFontSizeRef(size, ranges); } + /// + /// Enqueue a texture to be disposed at the end of the frame. + /// + /// The texture. + public void EnqueueDeferredDispose(DalamudTextureWrap wrap) + { + this.deferredDisposeTextures.Add(wrap); + } + private static void ShowFontError(string path) { Util.Fatal($"One or more files required by XIVLauncher were not found.\nPlease restart and report this error if it occurs again.\n\n{path}", "Error"); @@ -549,6 +563,13 @@ internal class InterfaceManager : IDisposable, IServiceType this.RenderImGui(); + foreach (var texture in this.deferredDisposeTextures) + { + texture.RealDispose(); + } + + this.deferredDisposeTextures.Clear(); + return this.presentHook.Original(swapChain, syncInterval, presentFlags); } From 0946f31a22eeeab5d5af6050fde3573eecbb3cc6 Mon Sep 17 00:00:00 2001 From: goat Date: Mon, 26 Dec 2022 14:57:58 +0100 Subject: [PATCH 21/51] chore: disable HTTP3 globally for .NET --- lib/CoreCLR/boot.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/CoreCLR/boot.cpp b/lib/CoreCLR/boot.cpp index e332650cc..e3db99c4f 100644 --- a/lib/CoreCLR/boot.cpp +++ b/lib/CoreCLR/boot.cpp @@ -51,6 +51,9 @@ int InitializeClrAndGetEntryPoint( SetEnvironmentVariable(L"DOTNET_TC_QuickJitForLoops", L"1"); SetEnvironmentVariable(L"DOTNET_ReadyToRun", L"1"); + // WINE does not support QUIC and we don't need it + SetEnvironmentVariable(L"DOTNET_SYSTEM_NET_HTTP_SOCKETSHTTPHANDLER_HTTP3SUPPORT", L"0"); + SetEnvironmentVariable(L"COMPlus_ETWEnabled", enable_etw ? L"1" : L"0"); wchar_t* dotnet_path; From 0dc58cce56b5892c2e0ec4ef1ac5f3dadfb1a236 Mon Sep 17 00:00:00 2001 From: goat Date: Mon, 2 Jan 2023 13:23:36 +0100 Subject: [PATCH 22/51] feat: show used video memory in dev bar --- .../Interface/Internal/DalamudInterface.cs | 7 ++++++- .../Interface/Internal/InterfaceManager.cs | 21 +++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs index 9c55b6452..68393bfa5 100644 --- a/Dalamud/Interface/Internal/DalamudInterface.cs +++ b/Dalamud/Interface/Internal/DalamudInterface.cs @@ -849,7 +849,12 @@ internal class DalamudInterface : IDisposable, IServiceType ImGui.BeginMenu(Util.GetGitHash(), false); ImGui.BeginMenu(this.FrameCount.ToString("000000"), false); ImGui.BeginMenu(ImGui.GetIO().Framerate.ToString("000"), false); - ImGui.BeginMenu($"{Util.FormatBytes(GC.GetTotalMemory(false))}", false); + ImGui.BeginMenu($"W:{Util.FormatBytes(GC.GetTotalMemory(false))}", false); + + var videoMem = Service.Get().GetD3dMemoryInfo(); + ImGui.BeginMenu( + !videoMem.HasValue ? $"V:???" : $"V:{Util.FormatBytes(videoMem.Value.Used)}", + false); ImGui.PopFont(); } diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs index 41bd8e9c7..650b1e00b 100644 --- a/Dalamud/Interface/Internal/InterfaceManager.cs +++ b/Dalamud/Interface/Internal/InterfaceManager.cs @@ -26,7 +26,6 @@ using ImGuiNET; using ImGuiScene; using PInvoke; using Serilog; -using SharpDX.Direct3D11; // general dev notes, here because it's easiest @@ -147,7 +146,7 @@ internal class InterfaceManager : IDisposable, IServiceType /// /// Gets the D3D11 device instance. /// - public Device? Device => this.scene?.Device; + public SharpDX.Direct3D11.Device? Device => this.scene?.Device; /// /// Gets the address handle to the main process window. @@ -409,6 +408,24 @@ internal class InterfaceManager : IDisposable, IServiceType this.deferredDisposeTextures.Add(wrap); } + /// + /// Get video memory information. + /// + /// The currently used video memory, or null if not available. + public (long Used, long Available)? GetD3dMemoryInfo() + { + if (this.Device == null) + return null; + + var dxgiDev = this.Device.QueryInterface(); + var dxgiAdapter = dxgiDev.Adapter.QueryInterfaceOrNull(); + if (dxgiAdapter == null) + return null; + + var memInfo = dxgiAdapter.QueryVideoMemoryInfo(0, SharpDX.DXGI.MemorySegmentGroup.Local); + return (memInfo.CurrentUsage, memInfo.CurrentReservation); + } + private static void ShowFontError(string path) { Util.Fatal($"One or more files required by XIVLauncher were not found.\nPlease restart and report this error if it occurs again.\n\n{path}", "Error"); From b6fc0b877b95c11eacd9a74b5d8845cf9bb742f1 Mon Sep 17 00:00:00 2001 From: Kaz Wolfe Date: Thu, 5 Jan 2023 23:47:46 -0800 Subject: [PATCH 23/51] feat: Add testing flag to plugin interface - Add IsTesting flag to allow plugins to determine if a testing version has been loaded. --- Dalamud/Plugin/DalamudPluginInterface.cs | 19 ++++++++++++++++--- Dalamud/Plugin/Internal/Types/LocalPlugin.cs | 6 ++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Dalamud/Plugin/DalamudPluginInterface.cs b/Dalamud/Plugin/DalamudPluginInterface.cs index aac4376ea..7e39a85d7 100644 --- a/Dalamud/Plugin/DalamudPluginInterface.cs +++ b/Dalamud/Plugin/DalamudPluginInterface.cs @@ -43,7 +43,7 @@ public sealed class DalamudPluginInterface : IDisposable /// The reason the plugin was loaded. /// A value indicating whether this is a dev plugin. /// The repository from which the plugin is installed. - internal DalamudPluginInterface(string pluginName, FileInfo assemblyLocation, PluginLoadReason reason, bool isDev, string sourceRepository) + internal DalamudPluginInterface(string pluginName, FileInfo assemblyLocation, PluginLoadReason reason, bool isDev, LocalPluginManifest manifest) { var configuration = Service.Get(); var dataManager = Service.Get(); @@ -56,7 +56,8 @@ public sealed class DalamudPluginInterface : IDisposable this.configs = Service.Get().PluginConfigs; this.Reason = reason; this.IsDev = isDev; - this.SourceRepository = isDev ? LocalPluginManifest.FlagDevPlugin : sourceRepository; + this.SourceRepository = isDev ? LocalPluginManifest.FlagDevPlugin : manifest.InstalledFromUrl; + this.IsTesting = manifest.Testing; this.LoadTime = DateTime.Now; this.LoadTimeUTC = DateTime.UtcNow; @@ -97,7 +98,11 @@ public sealed class DalamudPluginInterface : IDisposable public PluginLoadReason Reason { get; } /// - /// Gets the custom repository from which this plugin is installed, , or . + /// Gets the repository from which this plugin was installed. + /// + /// If a plugin was installed from the official/main repository, this will return the value of + /// . Developer plugins will return the value of + /// . /// public string SourceRepository { get; } @@ -106,6 +111,14 @@ public sealed class DalamudPluginInterface : IDisposable /// public bool IsDev { get; } + /// + /// Gets a value indicating whether this is a testing release of a plugin. + /// + /// + /// Dev plugins have undefined behavior for this value, but can be expected to return false. + /// + public bool IsTesting { get; } + /// /// Gets the time that this plugin was loaded. /// diff --git a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs index b49f5799c..7fae1b079 100644 --- a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs +++ b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs @@ -15,7 +15,6 @@ using Dalamud.Logging.Internal; using Dalamud.Plugin.Internal.Exceptions; using Dalamud.Plugin.Internal.Loader; using Dalamud.Utility; -using Dalamud.Utility.Signatures; namespace Dalamud.Plugin.Internal.Types; @@ -397,11 +396,10 @@ internal class LocalPlugin : IDisposable } // Update the location for the Location and CodeBase patches - PluginManager.PluginLocations[this.pluginType.Assembly.FullName] = - new PluginPatchData(this.DllFile); + PluginManager.PluginLocations[this.pluginType.Assembly.FullName] = new PluginPatchData(this.DllFile); this.DalamudInterface = - new DalamudPluginInterface(this.pluginAssembly.GetName().Name!, this.DllFile, reason, this.IsDev, this.Manifest.InstalledFromUrl); + new DalamudPluginInterface(this.pluginAssembly.GetName().Name!, this.DllFile, reason, this.IsDev, this.Manifest); if (this.Manifest.LoadSync && this.Manifest.LoadRequiredState is 0 or 1) { From bc3dcdfad7793343a682310d667ed55be663a2a7 Mon Sep 17 00:00:00 2001 From: goaaats Date: Fri, 6 Jan 2023 22:32:44 +0100 Subject: [PATCH 24/51] feat: settings window rework --- Dalamud/Game/Gui/GameGui.cs | 19 +- Dalamud/Interface/Internal/DalamudCommands.cs | 10 - .../Interface/Internal/DalamudInterface.cs | 64 +- .../Internal/Windows/ConsoleWindow.cs | 2 +- .../Windows/Settings/SettingsEntry.cs | 52 + .../Internal/Windows/Settings/SettingsTab.cs | 72 ++ .../Windows/Settings/SettingsWindow.cs | 232 +++++ .../Tabs/SettingsTabAbout.cs} | 119 +-- .../Windows/Settings/Tabs/SettingsTabDtr.cs | 162 +++ .../Settings/Tabs/SettingsTabExperimental.cs | 59 ++ .../Settings/Tabs/SettingsTabGeneral.cs | 92 ++ .../Windows/Settings/Tabs/SettingsTabLook.cs | 194 ++++ .../Settings/Widgets/ButtonSettingsEntry.cs | 41 + .../Widgets/DevPluginsSettingsEntry.cs | 184 ++++ .../Settings/Widgets/GapSettingsEntry.cs | 40 + .../Settings/Widgets/HintSettingsEntry.cs | 34 + .../Widgets/LanguageChooserSettingsEntry.cs | 74 ++ .../Settings/Widgets/SettingsEntry{T}.cs | 174 ++++ .../Widgets/ThirdRepoSettingsEntry.cs | 193 ++++ .../Internal/Windows/SettingsWindow.cs | 982 ------------------ Dalamud/Plugin/Internal/PluginManager.cs | 2 +- Dalamud/Utility/EnumExtensions.cs | 7 +- 22 files changed, 1724 insertions(+), 1084 deletions(-) create mode 100644 Dalamud/Interface/Internal/Windows/Settings/SettingsEntry.cs create mode 100644 Dalamud/Interface/Internal/Windows/Settings/SettingsTab.cs create mode 100644 Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs rename Dalamud/Interface/Internal/Windows/{CreditsWindow.cs => Settings/Tabs/SettingsTabAbout.cs} (70%) create mode 100644 Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabDtr.cs create mode 100644 Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs create mode 100644 Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabGeneral.cs create mode 100644 Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs create mode 100644 Dalamud/Interface/Internal/Windows/Settings/Widgets/ButtonSettingsEntry.cs create mode 100644 Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs create mode 100644 Dalamud/Interface/Internal/Windows/Settings/Widgets/GapSettingsEntry.cs create mode 100644 Dalamud/Interface/Internal/Windows/Settings/Widgets/HintSettingsEntry.cs create mode 100644 Dalamud/Interface/Internal/Windows/Settings/Widgets/LanguageChooserSettingsEntry.cs create mode 100644 Dalamud/Interface/Internal/Windows/Settings/Widgets/SettingsEntry{T}.cs create mode 100644 Dalamud/Interface/Internal/Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs delete mode 100644 Dalamud/Interface/Internal/Windows/SettingsWindow.cs diff --git a/Dalamud/Game/Gui/GameGui.cs b/Dalamud/Game/Gui/GameGui.cs index 6b9be88b4..18f59c75a 100644 --- a/Dalamud/Game/Gui/GameGui.cs +++ b/Dalamud/Game/Gui/GameGui.cs @@ -363,7 +363,7 @@ public sealed unsafe class GameGui : IDisposable, IServiceType /// /// The addon address. /// A pointer to the agent interface. - public unsafe IntPtr FindAgentInterface(IntPtr addonPtr) + public IntPtr FindAgentInterface(IntPtr addonPtr) { if (addonPtr == IntPtr.Zero) return IntPtr.Zero; @@ -411,11 +411,26 @@ public sealed unsafe class GameGui : IDisposable, IServiceType this.utf8StringFromSequenceHook.Dispose(); } + /// + /// Indicates if the game is on the title screen. + /// + /// A value indicating whether or not the game is on the title screen. + internal bool IsOnTitleScreen() + { + var charaSelect = this.GetAddonByName("CharaSelect", 1); + var charaMake = this.GetAddonByName("CharaMake", 1); + var titleDcWorldMap = this.GetAddonByName("TitleDCWorldMap", 1); + if (charaMake != nint.Zero || charaSelect != nint.Zero || titleDcWorldMap != nint.Zero) + return false; + + return !Service.Get().IsLoggedIn; + } + /// /// Set the current background music. /// /// The background music key. - public void SetBgm(ushort bgmKey) => this.setGlobalBgmHook.Original(bgmKey, 0, 0, 0, 0, 0); + internal void SetBgm(ushort bgmKey) => this.setGlobalBgmHook.Original(bgmKey, 0, 0, 0, 0, 0); /// /// Reset the stored "UI hide" state. diff --git a/Dalamud/Interface/Internal/DalamudCommands.cs b/Dalamud/Interface/Internal/DalamudCommands.cs index 2d49a8163..7855f9c54 100644 --- a/Dalamud/Interface/Internal/DalamudCommands.cs +++ b/Dalamud/Interface/Internal/DalamudCommands.cs @@ -101,11 +101,6 @@ internal class DalamudCommands : IServiceType HelpMessage = Loc.Localize("DalamudInstallerHelp", "Open the plugin installer"), }); - commandManager.AddHandler("/xlcredits", new CommandInfo(this.OnOpenCreditsCommand) - { - HelpMessage = Loc.Localize("DalamudCreditsHelp", "Opens the credits for dalamud."), - }); - commandManager.AddHandler("/xllanguage", new CommandInfo(this.OnSetLanguageCommand) { HelpMessage = @@ -328,11 +323,6 @@ internal class DalamudCommands : IServiceType Service.Get().TogglePluginInstallerWindow(); } - private void OnOpenCreditsCommand(string command, string arguments) - { - Service.Get().ToggleCreditsWindow(); - } - private void OnSetLanguageCommand(string command, string arguments) { var chatGui = Service.Get(); diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs index 68393bfa5..14d8f10de 100644 --- a/Dalamud/Interface/Internal/DalamudInterface.cs +++ b/Dalamud/Interface/Internal/DalamudInterface.cs @@ -12,11 +12,13 @@ using Dalamud.Configuration.Internal; using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.Gui; using Dalamud.Game.Internal; +using Dalamud.Interface.Animation.EasingFunctions; using Dalamud.Interface.Colors; using Dalamud.Interface.Internal.ManagedAsserts; using Dalamud.Interface.Internal.Windows; using Dalamud.Interface.Internal.Windows.PluginInstaller; using Dalamud.Interface.Internal.Windows.SelfTest; +using Dalamud.Interface.Internal.Windows.Settings; using Dalamud.Interface.Internal.Windows.StyleEditor; using Dalamud.Interface.Style; using Dalamud.Interface.Windowing; @@ -40,12 +42,13 @@ namespace Dalamud.Interface.Internal; [ServiceManager.EarlyLoadedService] internal class DalamudInterface : IDisposable, IServiceType { + private const float CreditsDarkeningMaxAlpha = 0.8f; + private static readonly ModuleLog Log = new("DUI"); private readonly ChangelogWindow changelogWindow; private readonly ColorDemoWindow colorDemoWindow; private readonly ComponentDemoWindow componentDemoWindow; - private readonly CreditsWindow creditsWindow; private readonly DataWindow dataWindow; private readonly GamepadModeNotifierWindow gamepadModeNotifierWindow; private readonly ImeWindow imeWindow; @@ -62,6 +65,9 @@ internal class DalamudInterface : IDisposable, IServiceType private readonly TextureWrap logoTexture; private readonly TextureWrap tsmLogoTexture; + private bool isCreditsDarkening = false; + private OutCubic creditsDarkeningAnimation = new(TimeSpan.FromSeconds(10)); + #if DEBUG private bool isImGuiDrawDevMenu = true; #else @@ -90,7 +96,6 @@ internal class DalamudInterface : IDisposable, IServiceType this.changelogWindow = new ChangelogWindow() { IsOpen = false }; this.colorDemoWindow = new ColorDemoWindow() { IsOpen = false }; this.componentDemoWindow = new ComponentDemoWindow() { IsOpen = false }; - this.creditsWindow = new CreditsWindow() { IsOpen = false }; this.dataWindow = new DataWindow() { IsOpen = false }; this.gamepadModeNotifierWindow = new GamepadModeNotifierWindow() { IsOpen = false }; this.imeWindow = new ImeWindow() { IsOpen = false }; @@ -107,7 +112,6 @@ internal class DalamudInterface : IDisposable, IServiceType this.WindowSystem.AddWindow(this.changelogWindow); this.WindowSystem.AddWindow(this.colorDemoWindow); this.WindowSystem.AddWindow(this.componentDemoWindow); - this.WindowSystem.AddWindow(this.creditsWindow); this.WindowSystem.AddWindow(this.dataWindow); this.WindowSystem.AddWindow(this.gamepadModeNotifierWindow); this.WindowSystem.AddWindow(this.imeWindow); @@ -147,6 +151,9 @@ internal class DalamudInterface : IDisposable, IServiceType { tsm.AddEntryCore(Loc.Localize("TSMDalamudDevMenu", "Developer Menu"), this.tsmLogoTexture, () => this.isImGuiDrawDevMenu = true); } + + this.creditsDarkeningAnimation.Point1 = Vector2.Zero; + this.creditsDarkeningAnimation.Point2 = new Vector2(CreditsDarkeningMaxAlpha); } /// @@ -176,7 +183,6 @@ internal class DalamudInterface : IDisposable, IServiceType this.WindowSystem.RemoveAllWindows(); this.changelogWindow.Dispose(); - this.creditsWindow.Dispose(); this.consoleWindow.Dispose(); this.pluginWindow.Dispose(); this.titleScreenMenuWindow.Dispose(); @@ -202,11 +208,6 @@ internal class DalamudInterface : IDisposable, IServiceType /// public void OpenComponentDemoWindow() => this.componentDemoWindow.IsOpen = true; - /// - /// Opens the . - /// - public void OpenCreditsWindow() => this.creditsWindow.IsOpen = true; - /// /// Opens the . /// @@ -313,11 +314,6 @@ internal class DalamudInterface : IDisposable, IServiceType /// public void ToggleComponentDemoWindow() => this.componentDemoWindow.Toggle(); - /// - /// Toggles the . - /// - public void ToggleCreditsWindow() => this.creditsWindow.Toggle(); - /// /// Toggles the . /// @@ -388,6 +384,18 @@ internal class DalamudInterface : IDisposable, IServiceType #endregion + /// + /// Toggle the screen darkening effect used for the credits. + /// + /// Whether or not to turn the effect on. + public void SetCreditsDarkeningAnimation(bool status) + { + this.isCreditsDarkening = status; + + if (status) + this.creditsDarkeningAnimation.Restart(); + } + private void OnDraw() { this.FrameCount++; @@ -430,6 +438,9 @@ internal class DalamudInterface : IDisposable, IServiceType if (this.isImGuiTestWindowsInMonospace) ImGui.PopFont(); + if (this.isCreditsDarkening) + this.DrawCreditsDarkeningAnimation(); + // Release focus of any ImGui window if we click into the game. var io = ImGui.GetIO(); if (!io.WantCaptureMouse && (User32.GetKeyState((int)User32.VirtualKey.VK_LBUTTON) & 0x8000) != 0) @@ -443,6 +454,26 @@ internal class DalamudInterface : IDisposable, IServiceType } } + private void DrawCreditsDarkeningAnimation() + { + ImGui.PushStyleVar(ImGuiStyleVar.WindowRounding, 0f); + ImGui.SetNextWindowPos(new Vector2(0, 0)); + ImGui.SetNextWindowSize(ImGuiHelpers.MainViewport.Size); + ImGuiHelpers.ForceNextWindowMainViewport(); + + this.creditsDarkeningAnimation.Update(); + ImGui.SetNextWindowBgAlpha(Math.Min(this.creditsDarkeningAnimation.EasedPoint.X, CreditsDarkeningMaxAlpha)); + + ImGui.Begin( + "###CreditsDarkenWindow", + ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.NoDocking | ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoMove | + ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.NoBringToFrontOnFocus | + ImGuiWindowFlags.NoNav); + ImGui.End(); + + ImGui.PopStyleVar(); + } + private void DrawHiddenDevMenuOpener() { var condition = Service.Get(); @@ -573,11 +604,6 @@ internal class DalamudInterface : IDisposable, IServiceType this.OpenDataWindow(); } - if (ImGui.MenuItem("Open Credits window")) - { - this.OpenCreditsWindow(); - } - if (ImGui.MenuItem("Open Settings window")) { this.OpenSettings(); diff --git a/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs b/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs index 0d19a340a..d2d51b8d6 100644 --- a/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs +++ b/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs @@ -52,7 +52,7 @@ internal class ConsoleWindow : Window, IDisposable /// Initializes a new instance of the class. /// public ConsoleWindow() - : base("Dalamud Console") + : base("Dalamud Console", ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse) { var configuration = Service.Get(); diff --git a/Dalamud/Interface/Internal/Windows/Settings/SettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/SettingsEntry.cs new file mode 100644 index 000000000..5e1dc7884 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/SettingsEntry.cs @@ -0,0 +1,52 @@ +using System; + +namespace Dalamud.Interface.Internal.Windows.Settings; + +/// +/// Basic, drawable settings entry. +/// +public abstract class SettingsEntry +{ + /// + /// Gets or sets the public, searchable name of this settings entry. + /// + public string? Name { get; protected set; } + + /// + /// Gets or sets a value indicating whether or not this entry is valid. + /// + public virtual bool IsValid { get; protected set; } = true; + + /// + /// Gets or sets a value indicating whether or not this entry is visible. + /// + public virtual bool IsVisible { get; protected set; } = true; + + /// + /// Gets the ID of this settings entry, used for ImGui uniqueness. + /// + protected Guid Id { get; } = Guid.NewGuid(); + + /// + /// Load this setting. + /// + public abstract void Load(); + + /// + /// Save this setting. + /// + public abstract void Save(); + + /// + /// Draw this setting control. + /// + public abstract void Draw(); + + /// + /// Function to be called when the tab is closed. + /// + public virtual void OnClose() + { + // ignored + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/SettingsTab.cs b/Dalamud/Interface/Internal/Windows/Settings/SettingsTab.cs new file mode 100644 index 000000000..16b7749cb --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/SettingsTab.cs @@ -0,0 +1,72 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Dalamud.Interface.Internal.Windows.Settings; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")] +public abstract class SettingsTab : IDisposable +{ + public abstract SettingsEntry[] Entries { get; } + + public abstract string Title { get; } + + public bool IsOpen { get; set; } = false; + + public virtual bool IsVisible { get; } = true; + + public virtual void OnOpen() + { + // ignored + } + + public virtual void OnClose() + { + foreach (var settingsEntry in this.Entries) + { + settingsEntry.OnClose(); + } + } + + public virtual void Draw() + { + foreach (var settingsEntry in this.Entries) + { + if (settingsEntry.IsVisible) + settingsEntry.Draw(); + + ImGuiHelpers.ScaledDummy(5); + } + + ImGuiHelpers.ScaledDummy(15); + } + + public virtual void Load() + { + foreach (var settingsEntry in this.Entries) + { + settingsEntry.Load(); + } + } + + public virtual void Save() + { + foreach (var settingsEntry in this.Entries) + { + settingsEntry.Save(); + } + } + + public virtual void Discard() + { + foreach (var settingsEntry in this.Entries) + { + settingsEntry.Load(); + } + } + + /// + public virtual void Dispose() + { + // ignored + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs b/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs new file mode 100644 index 000000000..24423b48c --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs @@ -0,0 +1,232 @@ +using System.Linq; +using System.Numerics; + +using CheapLoc; +using Dalamud.Configuration.Internal; +using Dalamud.Interface.Colors; +using Dalamud.Interface.Internal.Windows.Settings.Tabs; +using Dalamud.Interface.Windowing; +using Dalamud.Plugin.Internal; +using Dalamud.Utility; +using ImGuiNET; + +namespace Dalamud.Interface.Internal.Windows.Settings; + +/// +/// The window that allows for general configuration of Dalamud itself. +/// +internal class SettingsWindow : Window +{ + private readonly SettingsTab[] tabs = + { + new SettingsTabGeneral(), + new SettingsTabLook(), + new SettingsTabDtr(), + new SettingsTabExperimental(), + new SettingsTabAbout(), + }; + + private string searchInput = string.Empty; + + /// + /// Initializes a new instance of the class. + /// + public SettingsWindow() + : base(Loc.Localize("DalamudSettingsHeader", "Dalamud Settings") + "###XlSettings2", ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoScrollbar) + { + this.Size = new Vector2(740, 550); + this.SizeConstraints = new WindowSizeConstraints() + { + MinimumSize = new Vector2(752, 610), + MaximumSize = new Vector2(1780, 940), + }; + + this.SizeCondition = ImGuiCond.FirstUseEver; + } + + /// + public override void OnOpen() + { + foreach (var settingsTab in this.tabs) + { + settingsTab.Load(); + } + + this.searchInput = string.Empty; + + base.OnOpen(); + } + + /// + public override void OnClose() + { + var configuration = Service.Get(); + var interfaceManager = Service.Get(); + + var rebuildFont = + ImGui.GetIO().FontGlobalScale != configuration.GlobalUiScale || + interfaceManager.FontGamma != configuration.FontGammaLevel || + interfaceManager.UseAxis != configuration.UseAxisFontsFromGame; + + ImGui.GetIO().FontGlobalScale = configuration.GlobalUiScale; + interfaceManager.FontGammaOverride = null; + interfaceManager.UseAxisOverride = null; + + if (rebuildFont) + interfaceManager.RebuildFonts(); + + foreach (var settingsTab in this.tabs) + { + if (settingsTab.IsOpen) + settingsTab.OnClose(); + + settingsTab.IsOpen = false; + } + } + + /// + public override void Draw() + { + var windowSize = ImGui.GetWindowSize(); + + if (ImGui.BeginTabBar("###settingsTabs")) + { + if (string.IsNullOrEmpty(this.searchInput)) + { + foreach (var settingsTab in this.tabs.Where(x => x.IsVisible)) + { + if (ImGui.BeginTabItem(settingsTab.Title)) + { + if (!settingsTab.IsOpen) + { + settingsTab.IsOpen = true; + settingsTab.OnOpen(); + } + + if (ImGui.BeginChild($"###settings_scrolling_{settingsTab.Title}", new Vector2(-1, -1), false)) + { + settingsTab.Draw(); + } + + ImGui.EndChild(); + ImGui.EndTabItem(); + } + else if (settingsTab.IsOpen) + { + settingsTab.IsOpen = false; + settingsTab.OnClose(); + } + } + } + else + { + if (ImGui.BeginTabItem("Search Results")) + { + var any = false; + + foreach (var settingsTab in this.tabs.Where(x => x.IsVisible)) + { + var eligible = settingsTab.Entries.Where(x => !x.Name.IsNullOrEmpty() && x.Name.ToLower().Contains(this.searchInput.ToLower())).ToArray(); + + if (!eligible.Any()) + continue; + + any = true; + + ImGui.TextColored(ImGuiColors.DalamudGrey, settingsTab.Title); + ImGui.Dummy(new Vector2(5)); + + foreach (var settingsTabEntry in eligible) + { + settingsTabEntry.Draw(); + ImGuiHelpers.ScaledDummy(3); + } + + ImGui.Separator(); + + ImGui.Dummy(new Vector2(10)); + } + + if (!any) + ImGui.TextColored(ImGuiColors.DalamudGrey, "No results found..."); + + ImGui.EndTabItem(); + } + } + } + + ImGui.SetCursorPos(windowSize - ImGuiHelpers.ScaledVector2(70)); + + if (ImGui.BeginChild("###settingsFinishButton")) + { + ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 100f); + ImGui.PushFont(InterfaceManager.IconFont); + + var invalid = this.tabs.Any(x => x.Entries.Any(y => !y.IsValid)); + if (invalid) + ImGui.BeginDisabled(); + + if (ImGui.Button(FontAwesomeIcon.Save.ToIconString(), new Vector2(40))) + { + this.Save(); + + this.IsOpen = false; + } + + ImGui.PopStyleVar(); + ImGui.PopFont(); + + if (ImGui.IsItemHovered()) + ImGui.SetTooltip(Loc.Localize("DalamudSettingsSaveAndExit", "Save changes and close")); + + if (invalid) + ImGui.EndDisabled(); + } + + ImGui.EndChild(); + + ImGui.SetCursorPos(new Vector2(windowSize.X - 250, ImGui.GetTextLineHeightWithSpacing() + (ImGui.GetStyle().FramePadding.Y * 2))); + ImGui.SetNextItemWidth(240); + ImGui.InputTextWithHint("###searchInput", "Search for settings...", ref this.searchInput, 100); + } + + private void Save() + { + var configuration = Service.Get(); + + foreach (var settingsTab in this.tabs) + { + settingsTab.Save(); + } + + // Apply docking flag + if (!configuration.IsDocking) + { + ImGui.GetIO().ConfigFlags &= ~ImGuiConfigFlags.DockingEnable; + } + else + { + ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.DockingEnable; + } + + // NOTE (Chiv) Toggle gamepad navigation via setting + if (!configuration.IsGamepadNavigationEnabled) + { + ImGui.GetIO().BackendFlags &= ~ImGuiBackendFlags.HasGamepad; + ImGui.GetIO().ConfigFlags &= ~ImGuiConfigFlags.NavEnableSetMousePos; + + var di = Service.Get(); + di.CloseGamepadModeNotifierWindow(); + } + else + { + ImGui.GetIO().BackendFlags |= ImGuiBackendFlags.HasGamepad; + ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.NavEnableSetMousePos; + } + + configuration.QueueSave(); + + _ = Service.Get().ReloadPluginMastersAsync(); + Service.Get().RebuildFonts(); + } +} diff --git a/Dalamud/Interface/Internal/Windows/CreditsWindow.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAbout.cs similarity index 70% rename from Dalamud/Interface/Internal/Windows/CreditsWindow.cs rename to Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAbout.cs index 83857a826..3ad67a841 100644 --- a/Dalamud/Interface/Internal/Windows/CreditsWindow.cs +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAbout.cs @@ -1,23 +1,22 @@ -using System; +using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Numerics; +using CheapLoc; using Dalamud.Game.Gui; using Dalamud.Interface.GameFonts; -using Dalamud.Interface.Windowing; using Dalamud.Plugin.Internal; using Dalamud.Utility; using ImGuiNET; using ImGuiScene; -namespace Dalamud.Interface.Internal.Windows; +namespace Dalamud.Interface.Internal.Windows.Settings.Tabs; -/// -/// A window documenting contributors to the project. -/// -internal class CreditsWindow : Window, IDisposable +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")] +public class SettingsTabAbout : SettingsTab { private const float CreditFps = 60.0f; private const string ThankYouText = "Thank you!"; @@ -27,7 +26,8 @@ A FFXIV Plugin Framework Version D{0} -created by: + +Created by: goat daemitus @@ -124,8 +124,15 @@ philpax We use these awesome libraries: +FFXIVClientStructs ({2}) +Copyright (c) 2021 aers +Licensed under the MIT License + Lumina by Adam -FFXIVClientStructs by aers ({2}) +Licensed under the WTFPL v2.0 + +Reloaded Libraries by Sewer56 +Licensed under the GNU Lesser General Public License v3.0 DotNetCorePlugins Copyright (c) Nate McMaster @@ -145,17 +152,20 @@ Licensed under the BSD 2-Clause License SRELL Copyright (c) 2012-2022, Nozomu Katoo +STB Libraries +Copyright (c) 2017 Sean Barrett +Licensed under the MIT License + Please see licenses.txt for more information. -Thanks to everyone in the XIVLauncher Discord server - +Thanks to everyone in the XIVLauncher Discord server! Join us at: https://discord.gg/3NMcUV5 -Dalamud is licensed under AGPL v3 or later -Contribute at: https://github.com/goatsoft/Dalamud +Dalamud is licensed under AGPL v3 or later. +Contribute at: https://github.com/goatcorp/Dalamud "; private readonly TextureWrap logoTexture; @@ -163,28 +173,22 @@ Contribute at: https://github.com/goatsoft/Dalamud private string creditsText; + private bool resetNow = false; private GameFontHandle? thankYouFont; - /// - /// Initializes a new instance of the class. - /// - public CreditsWindow() - : base("Dalamud Credits", ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoTitleBar, true) + public SettingsTabAbout() { var dalamud = Service.Get(); var interfaceManager = Service.Get(); - this.logoTexture = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "logo.png")); + this.logoTexture = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "logo.png"))!; this.creditsThrottler = new(); - - this.Size = new Vector2(500, 400); - this.SizeCondition = ImGuiCond.Always; - - this.PositionCondition = ImGuiCond.Always; - - this.BgAlpha = 0.8f; } + public override SettingsEntry[] Entries { get; } = { }; + + public override string Title => Loc.Localize("DalamudAbout", "About"); + /// public override void OnOpen() { @@ -195,7 +199,10 @@ Contribute at: https://github.com/goatsoft/Dalamud this.creditsText = string.Format(CreditsTextTempl, typeof(Dalamud).Assembly.GetName().Version, pluginCredits, Util.GetGitHashClientStructs()); - Service.Get().SetBgm(833); + var gg = Service.Get(); + if (!gg.IsOnTitleScreen()) + gg.SetBgm(833); + this.creditsThrottler.Restart(); if (this.thankYouFont == null) @@ -203,41 +210,36 @@ Contribute at: https://github.com/goatsoft/Dalamud var gfm = Service.Get(); this.thankYouFont = gfm.NewFontRef(new GameFontStyle(GameFontFamilyAndSize.TrumpGothic34)); } + + this.resetNow = true; + + Service.Get().SetCreditsDarkeningAnimation(true); } /// public override void OnClose() { this.creditsThrottler.Reset(); - Service.Get().SetBgm(9999); + + var gg = Service.Get(); + if (!gg.IsOnTitleScreen()) + gg.SetBgm(9999); + + Service.Get().SetCreditsDarkeningAnimation(false); } - /// - public override void PreDraw() - { - ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(0, 0)); - - base.PreDraw(); - } - - /// - public override void PostDraw() - { - ImGui.PopStyleVar(); - - base.PostDraw(); - } - - /// public override void Draw() { - var screenSize = ImGui.GetMainViewport().Size; var windowSize = ImGui.GetWindowSize(); - this.Position = (screenSize - windowSize) / 2; - ImGui.BeginChild("scrolling", Vector2.Zero, false, ImGuiWindowFlags.NoScrollbar); + if (this.resetNow) + { + ImGui.SetScrollY(0); + this.resetNow = false; + } + ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero); ImGuiHelpers.ScaledDummy(0, windowSize.Y + 20f); @@ -295,30 +297,13 @@ Contribute at: https://github.com/goatsoft/Dalamud ImGui.EndChild(); - ImGui.SetCursorPos(new Vector2(0)); - ImGui.BeginChild("button", Vector2.Zero, false, ImGuiWindowFlags.NoScrollbar); - - var closeButtonSize = new Vector2(30); - ImGui.PushFont(InterfaceManager.IconFont); - ImGui.SetCursorPos(new Vector2(windowSize.X - closeButtonSize.X - 5, 5)); - ImGui.PushStyleColor(ImGuiCol.Button, Vector4.Zero); - ImGui.PushStyleColor(ImGuiCol.ButtonHovered, Vector4.Zero); - ImGui.PushStyleColor(ImGuiCol.ButtonActive, Vector4.Zero); - - if (ImGui.Button(FontAwesomeIcon.Times.ToIconString(), closeButtonSize)) - { - this.IsOpen = false; - } - - ImGui.PopStyleColor(3); - ImGui.PopFont(); - ImGui.EndChild(); + base.Draw(); } /// /// Disposes of managed and unmanaged resources. /// - public void Dispose() + public override void Dispose() { this.logoTexture?.Dispose(); this.thankYouFont?.Dispose(); diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabDtr.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabDtr.cs new file mode 100644 index 000000000..85cb8219f --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabDtr.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +using CheapLoc; +using Dalamud.Configuration.Internal; +using Dalamud.Game.Gui.Dtr; +using Dalamud.Interface.Colors; +using Dalamud.Interface.Components; +using ImGuiNET; + +namespace Dalamud.Interface.Internal.Windows.Settings.Tabs; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")] +public class SettingsTabDtr : SettingsTab +{ + private List? dtrOrder; + private List? dtrIgnore; + private int dtrSpacing; + private bool dtrSwapDirection; + + public override SettingsEntry[] Entries { get; } = Array.Empty(); + + public override string Title => Loc.Localize("DalamudSettingsServerInfoBar", "Server Info Bar"); + + public override void Draw() + { + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarHint", "Plugins can put additional information into your server information bar(where world & time can be seen).\nYou can reorder and disable these here.")); + + ImGuiHelpers.ScaledDummy(10); + + var configuration = Service.Get(); + var dtrBar = Service.Get(); + + var order = configuration.DtrOrder!.Where(x => dtrBar.HasEntry(x)).ToList(); + var ignore = configuration.DtrIgnore!.Where(x => dtrBar.HasEntry(x)).ToList(); + var orderLeft = configuration.DtrOrder!.Where(x => !order.Contains(x)).ToList(); + var ignoreLeft = configuration.DtrIgnore!.Where(x => !ignore.Contains(x)).ToList(); + + if (order.Count == 0) + { + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarDidNone", "You have no plugins that use this feature.")); + } + + var isOrderChange = false; + for (var i = 0; i < order.Count; i++) + { + var title = order[i]; + + // TODO: Maybe we can also resort the rest of the bar in the future? + // var isRequired = search is Configuration.SearchSetting.Internal or Configuration.SearchSetting.MacroLinks; + + ImGui.PushFont(UiBuilder.IconFont); + + var arrowUpText = $"{FontAwesomeIcon.ArrowUp.ToIconString()}##{title}"; + if (i == 0) + { + ImGuiComponents.DisabledButton(arrowUpText); + } + else + { + if (ImGui.Button(arrowUpText)) + { + (order[i], order[i - 1]) = (order[i - 1], order[i]); + isOrderChange = true; + } + } + + ImGui.SameLine(); + + var arrowDownText = $"{FontAwesomeIcon.ArrowDown.ToIconString()}##{title}"; + if (i == order.Count - 1) + { + ImGuiComponents.DisabledButton(arrowDownText); + } + else + { + if (ImGui.Button(arrowDownText) && i != order.Count - 1) + { + (order[i], order[i + 1]) = (order[i + 1], order[i]); + isOrderChange = true; + } + } + + ImGui.PopFont(); + + ImGui.SameLine(); + + // if (isRequired) { + // ImGui.TextUnformatted($"Search in {name}"); + // } else { + + var isShown = ignore.All(x => x != title); + var nextIsShow = isShown; + if (ImGui.Checkbox($"{title}###dtrEntry{i}", ref nextIsShow) && nextIsShow != isShown) + { + if (nextIsShow) + ignore.Remove(title); + else + ignore.Add(title); + + dtrBar.MakeDirty(title); + } + + // } + } + + configuration.DtrOrder = order.Concat(orderLeft).ToList(); + configuration.DtrIgnore = ignore.Concat(ignoreLeft).ToList(); + + if (isOrderChange) + dtrBar.ApplySort(); + + ImGuiHelpers.ScaledDummy(10); + + ImGui.Text(Loc.Localize("DalamudSettingServerInfoBarSpacing", "Server Info Bar spacing")); + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarSpacingHint", "Configure the amount of space between entries in the server info bar here.")); + ImGui.SliderInt("Spacing", ref this.dtrSpacing, 0, 40); + + ImGui.Text(Loc.Localize("DalamudSettingServerInfoBarDirection", "Server Info Bar direction")); + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarDirectionHint", "If checked, the Server Info Bar elements will expand to the right instead of the left.")); + ImGui.Checkbox("Swap Direction", ref this.dtrSwapDirection); + + base.Draw(); + } + + public override void OnClose() + { + var configuration = Service.Get(); + configuration.DtrOrder = this.dtrOrder; + configuration.DtrIgnore = this.dtrIgnore; + + base.OnClose(); + } + + public override void Load() + { + var configuration = Service.Get(); + + this.dtrSpacing = configuration.DtrSpacing; + this.dtrSwapDirection = configuration.DtrSwapDirection; + + this.dtrOrder = configuration.DtrOrder; + this.dtrIgnore = configuration.DtrIgnore; + + base.Load(); + } + + public override void Save() + { + var configuration = Service.Get(); + + configuration.DtrSpacing = this.dtrSpacing; + configuration.DtrSwapDirection = this.dtrSwapDirection; + + this.dtrOrder = configuration.DtrOrder; + this.dtrIgnore = configuration.DtrIgnore; + + base.Save(); + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs new file mode 100644 index 000000000..a1c2c3336 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs @@ -0,0 +1,59 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +using CheapLoc; +using Dalamud.Configuration.Internal; +using Dalamud.Interface.Colors; +using Dalamud.Interface.Internal.Windows.PluginInstaller; +using Dalamud.Interface.Internal.Windows.Settings.Widgets; +using Dalamud.Plugin.Internal; +using Dalamud.Utility; + +namespace Dalamud.Interface.Internal.Windows.Settings.Tabs; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")] +public class SettingsTabExperimental : SettingsTab +{ + public override SettingsEntry[] Entries { get; } = + { + new SettingsEntry( + Loc.Localize("DalamudSettingsPluginTest", "Get plugin testing builds"), + string.Format( + Loc.Localize("DalamudSettingsPluginTestHint", "Receive testing prereleases for selected plugins.\nTo opt-in to testing builds for a plugin, you have to right click it in the \"{0}\" tab of the plugin installer and select \"{1}\"."), + PluginCategoryManager.Locs.Group_Installed, + PluginInstallerWindow.Locs.PluginContext_TestingOptIn), + c => c.DoPluginTest, + (v, c) => c.DoPluginTest = v), + new HintSettingsEntry( + Loc.Localize("DalamudSettingsPluginTestWarning", "Testing plugins may not have been vetted before being published. Please only enable this if you are aware of the risks."), + ImGuiColors.DalamudRed), + + new GapSettingsEntry(5), + + new ButtonSettingsEntry( + Loc.Localize("DalamudSettingsClearHidden", "Clear hidden plugins"), + Loc.Localize("DalamudSettingsClearHiddenHint", "Restore plugins you have previously hidden from the plugin installer."), + () => + { + Service.Get().HiddenPluginInternalName.Clear(); + Service.Get().RefilterPluginMasters(); + }), + + new GapSettingsEntry(5, true), + + new DevPluginsSettingsEntry(), + + new GapSettingsEntry(5, true), + + new ThirdRepoSettingsEntry(), + }; + + public override string Title => Loc.Localize("DalamudSettingsExperimental", "Experimental"); + + public override void Draw() + { + base.Draw(); + + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, "Total memory used by Dalamud & Plugins: " + Util.FormatBytes(GC.GetTotalMemory(false))); + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabGeneral.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabGeneral.cs new file mode 100644 index 000000000..7e5c9dd98 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabGeneral.cs @@ -0,0 +1,92 @@ +using System.Diagnostics.CodeAnalysis; + +using CheapLoc; +using Dalamud.Game.Text; +using Dalamud.Interface.Internal.Windows.Settings.Widgets; + +namespace Dalamud.Interface.Internal.Windows.Settings.Tabs; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")] +public class SettingsTabGeneral : SettingsTab +{ + public override SettingsEntry[] Entries { get; } = + { + new LanguageChooserSettingsEntry(), + + new GapSettingsEntry(5), + + new SettingsEntry( + Loc.Localize("DalamudSettingsChannel", "Dalamud Chat Channel"), + Loc.Localize("DalamudSettingsChannelHint", "Select the chat channel that is to be used for general Dalamud messages."), + c => c.GeneralChatType, + (v, c) => c.GeneralChatType = v, + warning: (v) => + { + // TODO: Maybe actually implement UI for the validity check... + if (v == XivChatType.None) + return Loc.Localize("DalamudSettingsChannelNone", "Do not pick \"None\"."); + + return null; + }), + + new GapSettingsEntry(5), + + new SettingsEntry( + Loc.Localize("DalamudSettingsWaitForPluginsOnStartup", "Wait for plugins before game loads"), + Loc.Localize("DalamudSettingsWaitForPluginsOnStartupHint", "Do not let the game load, until plugins are loaded."), + c => c.IsResumeGameAfterPluginLoad, + (v, c) => c.IsResumeGameAfterPluginLoad = v), + + new SettingsEntry( + Loc.Localize("DalamudSettingsFlash", "Flash FFXIV window on duty pop"), + Loc.Localize("DalamudSettingsFlashHint", "Flash the FFXIV window in your task bar when a duty is ready."), + c => c.DutyFinderTaskbarFlash, + (v, c) => c.DutyFinderTaskbarFlash = v), + + new SettingsEntry( + Loc.Localize("DalamudSettingsDutyFinderMessage", "Chatlog message on duty pop"), + Loc.Localize("DalamudSettingsDutyFinderMessageHint", "Send a message in FFXIV chat when a duty is ready."), + c => c.DutyFinderChatMessage, + (v, c) => c.DutyFinderChatMessage = v), + + new SettingsEntry( + Loc.Localize("DalamudSettingsPrintPluginsWelcomeMsg", "Display loaded plugins in the welcome message"), + Loc.Localize("DalamudSettingsPrintPluginsWelcomeMsgHint", "Display loaded plugins in FFXIV chat when logging in with a character."), + c => c.PrintPluginsWelcomeMsg, + (v, c) => c.PrintPluginsWelcomeMsg = v), + + new SettingsEntry( + Loc.Localize("DalamudSettingsAutoUpdatePlugins", "Auto-update plugins"), + Loc.Localize("DalamudSettingsAutoUpdatePluginsMsgHint", "Automatically update plugins when logging in with a character."), + c => c.AutoUpdatePlugins, + (v, c) => c.AutoUpdatePlugins = v), + + new SettingsEntry( + Loc.Localize("DalamudSettingsSystemMenu", "Dalamud buttons in system menu"), + Loc.Localize("DalamudSettingsSystemMenuMsgHint", "Add buttons for Dalamud plugins and settings to the system menu."), + c => c.DoButtonsSystemMenu, + (v, c) => c.DoButtonsSystemMenu = v), + + new SettingsEntry( + Loc.Localize("DalamudSettingsSystemMenu", "Dalamud buttons in system menu"), + Loc.Localize("DalamudSettingsSystemMenuMsgHint", "Add buttons for Dalamud plugins and settings to the system menu."), + c => c.DoButtonsSystemMenu, + (v, c) => c.DoButtonsSystemMenu = v), + + new SettingsEntry( + Loc.Localize("DalamudSettingsEnableRmtFiltering", "Enable RMT Filtering"), + Loc.Localize("DalamudSettingsEnableRmtFilteringMsgHint", "Enable Dalamud's built-in RMT ad filtering."), + c => !c.DisableRmtFiltering, + (v, c) => c.DisableRmtFiltering = !v), + + new GapSettingsEntry(5), + + new SettingsEntry( + Loc.Localize("DalamudSettingDoMbCollect", "Anonymously upload market board data"), + Loc.Localize("DalamudSettingDoMbCollectHint", "Anonymously provide data about in-game economics to Universalis when browsing the market board. This data can't be tied to you in any way and everyone benefits!"), + c => c.IsMbCollect, + (v, c) => c.IsMbCollect = v), + }; + + public override string Title => Loc.Localize("DalamudSettingsGeneral", "General"); +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs new file mode 100644 index 000000000..8b9ef9952 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs @@ -0,0 +1,194 @@ +using System.Diagnostics.CodeAnalysis; + +using CheapLoc; +using Dalamud.Configuration.Internal; +using Dalamud.Interface.Colors; +using Dalamud.Interface.Internal.Windows.Settings.Widgets; +using ImGuiNET; + +namespace Dalamud.Interface.Internal.Windows.Settings.Tabs; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")] +public class SettingsTabLook : SettingsTab +{ + private float globalUiScale; + private float fontGamma; + + public override SettingsEntry[] Entries { get; } = + { + new GapSettingsEntry(5), + + new ButtonSettingsEntry( + Loc.Localize("DalamudSettingsOpenStyleEditor", "Open Style Editor"), + Loc.Localize("DalamudSettingsStyleEditorHint", "Modify the look & feel of Dalamud windows."), + () => Service.Get().OpenStyleEditor()), + + new GapSettingsEntry(5), + + new SettingsEntry( + Loc.Localize("DalamudSettingToggleAxisFonts", "Use AXIS fonts as default Dalamud font"), + Loc.Localize("DalamudSettingToggleUiAxisFontsHint", "Use AXIS fonts (the game's main UI fonts) as default Dalamud font."), + c => c.UseAxisFontsFromGame, + (v, c) => c.UseAxisFontsFromGame = v, + v => + { + var im = Service.Get(); + im.UseAxisOverride = v; + im.RebuildFonts(); + }), + + new GapSettingsEntry(5, true), + + new HintSettingsEntry(Loc.Localize("DalamudSettingToggleUiHideOptOutNote", "Plugins may independently opt out of the settings below.")), + new GapSettingsEntry(3), + + new SettingsEntry( + Loc.Localize("DalamudSettingToggleUiHide", "Hide plugin UI when the game UI is toggled off"), + Loc.Localize("DalamudSettingToggleUiHideHint", "Hide any open windows by plugins when toggling the game overlay."), + c => c.ToggleUiHide, + (v, c) => c.ToggleUiHide = v), + + new SettingsEntry( + Loc.Localize("DalamudSettingToggleUiHideDuringCutscenes", "Hide plugin UI during cutscenes"), + Loc.Localize("DalamudSettingToggleUiHideDuringCutscenesHint", "Hide any open windows by plugins during cutscenes."), + c => c.ToggleUiHideDuringCutscenes, + (v, c) => c.ToggleUiHideDuringCutscenes = v), + + new SettingsEntry( + Loc.Localize("DalamudSettingToggleUiHideDuringGpose", "Hide plugin UI while gpose is active"), + Loc.Localize("DalamudSettingToggleUiHideDuringGposeHint", "Hide any open windows by plugins while gpose is active."), + c => c.ToggleUiHideDuringGpose, + (v, c) => c.ToggleUiHideDuringGpose = v), + + new GapSettingsEntry(5, true), + + new SettingsEntry( + Loc.Localize("DalamudSettingToggleFocusManagement", "Use escape to close Dalamud windows"), + Loc.Localize("DalamudSettingToggleFocusManagementHint", "This will cause Dalamud windows to behave like in-game windows when pressing escape.\nThey will close one after another until all are closed. May not work for all plugins."), + c => c.IsFocusManagementEnabled, + (v, c) => c.IsFocusManagementEnabled = v), + + // This is applied every frame in InterfaceManager::CheckViewportState() + new SettingsEntry( + Loc.Localize("DalamudSettingToggleViewports", "Enable multi-monitor windows"), + Loc.Localize("DalamudSettingToggleViewportsHint", "This will allow you move plugin windows onto other monitors.\nWill only work in Borderless Window or Windowed mode."), + c => !c.IsDisableViewport, + (v, c) => c.IsDisableViewport = !v), + + new SettingsEntry( + Loc.Localize("DalamudSettingToggleDocking", "Enable window docking"), + Loc.Localize("DalamudSettingToggleDockingHint", "This will allow you to fuse and tab plugin windows."), + c => c.IsDocking, + (v, c) => c.IsDocking = v), + + new SettingsEntry( + Loc.Localize("DalamudSettingToggleGamepadNavigation", "Control plugins via gamepad"), + Loc.Localize("DalamudSettingToggleGamepadNavigationHint", "This will allow you to toggle between game and plugin navigation via L1+L3.\nToggle the PluginInstaller window via R3 if ImGui navigation is enabled."), + c => c.IsGamepadNavigationEnabled, + (v, c) => c.IsGamepadNavigationEnabled = v), + + new SettingsEntry( + Loc.Localize("DalamudSettingToggleTsm", "Show title screen menu"), + Loc.Localize("DalamudSettingToggleTsmHint", "This will allow you to access certain Dalamud and Plugin functionality from the title screen."), + c => c.ShowTsm, + (v, c) => c.ShowTsm = v), + }; + + public override string Title => Loc.Localize("DalamudSettingsVisual", "Look & Feel"); + + public override void Draw() + { + var interfaceManager = Service.Get(); + + ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3); + ImGui.Text(Loc.Localize("DalamudSettingsGlobalUiScale", "Global Font Scale")); + ImGui.SameLine(); + ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 3); + if (ImGui.Button("9.6pt##DalamudSettingsGlobalUiScaleReset96")) + { + this.globalUiScale = 9.6f / 12.0f; + ImGui.GetIO().FontGlobalScale = this.globalUiScale; + interfaceManager.RebuildFonts(); + } + + ImGui.SameLine(); + if (ImGui.Button("12pt##DalamudSettingsGlobalUiScaleReset12")) + { + this.globalUiScale = 1.0f; + ImGui.GetIO().FontGlobalScale = this.globalUiScale; + interfaceManager.RebuildFonts(); + } + + ImGui.SameLine(); + if (ImGui.Button("14pt##DalamudSettingsGlobalUiScaleReset14")) + { + this.globalUiScale = 14.0f / 12.0f; + ImGui.GetIO().FontGlobalScale = this.globalUiScale; + interfaceManager.RebuildFonts(); + } + + ImGui.SameLine(); + if (ImGui.Button("18pt##DalamudSettingsGlobalUiScaleReset18")) + { + this.globalUiScale = 18.0f / 12.0f; + ImGui.GetIO().FontGlobalScale = this.globalUiScale; + interfaceManager.RebuildFonts(); + } + + ImGui.SameLine(); + if (ImGui.Button("36pt##DalamudSettingsGlobalUiScaleReset36")) + { + this.globalUiScale = 36.0f / 12.0f; + ImGui.GetIO().FontGlobalScale = this.globalUiScale; + interfaceManager.RebuildFonts(); + } + + var globalUiScaleInPt = 12f * this.globalUiScale; + if (ImGui.DragFloat("##DalamudSettingsGlobalUiScaleDrag", ref globalUiScaleInPt, 0.1f, 9.6f, 36f, "%.1fpt", ImGuiSliderFlags.AlwaysClamp)) + { + this.globalUiScale = globalUiScaleInPt / 12f; + ImGui.GetIO().FontGlobalScale = this.globalUiScale; + interfaceManager.RebuildFonts(); + } + + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsGlobalUiScaleHint", "Scale text in all XIVLauncher UI elements - this is useful for 4K displays.")); + + ImGuiHelpers.ScaledDummy(5); + + ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3); + ImGui.Text(Loc.Localize("DalamudSettingsFontGamma", "Font Gamma")); + ImGui.SameLine(); + ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 3); + if (ImGui.Button(Loc.Localize("DalamudSettingsIndividualConfigResetToDefaultValue", "Reset") + "##DalamudSettingsFontGammaReset")) + { + this.fontGamma = 1.4f; + interfaceManager.FontGammaOverride = this.fontGamma; + interfaceManager.RebuildFonts(); + } + + if (ImGui.DragFloat("##DalamudSettingsFontGammaDrag", ref this.fontGamma, 0.005f, 0.3f, 3f, "%.2f", ImGuiSliderFlags.AlwaysClamp)) + { + interfaceManager.FontGammaOverride = this.fontGamma; + interfaceManager.RebuildFonts(); + } + + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsFontGammaHint", "Changes the thickness of text.")); + + base.Draw(); + } + + public override void Load() + { + this.globalUiScale = Service.Get().GlobalUiScale; + this.fontGamma = Service.Get().FontGammaLevel; + + base.Load(); + } + + public override void Save() + { + Service.Get().GlobalUiScale = this.globalUiScale; + + base.Save(); + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/ButtonSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/ButtonSettingsEntry.cs new file mode 100644 index 000000000..9c635fb99 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/ButtonSettingsEntry.cs @@ -0,0 +1,41 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +using Dalamud.Interface.Colors; +using ImGuiNET; + +namespace Dalamud.Interface.Internal.Windows.Settings.Widgets; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")] +public class ButtonSettingsEntry : SettingsEntry +{ + private readonly string description; + private readonly Action runs; + + public ButtonSettingsEntry(string name, string description, Action runs) + { + this.description = description; + this.runs = runs; + this.Name = name; + } + + public override void Load() + { + // ignored + } + + public override void Save() + { + // ignored + } + + public override void Draw() + { + if (ImGui.Button(this.Name)) + { + this.runs.Invoke(); + } + + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, this.description); + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs new file mode 100644 index 000000000..b1a231335 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Numerics; +using System.Threading.Tasks; + +using CheapLoc; +using Dalamud.Configuration; +using Dalamud.Configuration.Internal; +using Dalamud.Interface.Colors; +using Dalamud.Interface.Components; +using Dalamud.Plugin.Internal; +using ImGuiNET; + +namespace Dalamud.Interface.Internal.Windows.Settings.Widgets; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")] +public class DevPluginsSettingsEntry : SettingsEntry +{ + private List devPluginLocations = new(); + private bool devPluginLocationsChanged; + private string devPluginTempLocation = string.Empty; + private string devPluginLocationAddError = string.Empty; + + public DevPluginsSettingsEntry() + { + this.Name = Loc.Localize("DalamudSettingsDevPluginLocation", "Dev Plugin Locations"); + } + + public override void OnClose() + { + this.devPluginLocations = + Service.Get().DevPluginLoadLocations.Select(x => x.Clone()).ToList(); + } + + public override void Load() + { + this.devPluginLocations = + Service.Get().DevPluginLoadLocations.Select(x => x.Clone()).ToList(); + this.devPluginLocationsChanged = false; + } + + public override void Save() + { + Service.Get().DevPluginLoadLocations = this.devPluginLocations.Select(x => x.Clone()).ToList(); + + if (this.devPluginLocationsChanged) + { + Service.Get().ScanDevPlugins(); + this.devPluginLocationsChanged = false; + } + } + + public override void Draw() + { + ImGui.Text(this.Name); + if (this.devPluginLocationsChanged) + { + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen); + ImGui.SameLine(); + ImGui.Text(Loc.Localize("DalamudSettingsChanged", "(Changed)")); + ImGui.PopStyleColor(); + } + + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsDevPluginLocationsHint", "Add additional dev plugin load locations.\nThese can be either the directory or DLL path.")); + + ImGuiHelpers.ScaledDummy(5); + + ImGui.Columns(4); + ImGui.SetColumnWidth(0, 18 + (5 * ImGuiHelpers.GlobalScale)); + ImGui.SetColumnWidth(1, ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X - (18 + 16 + 14) - ((5 + 45 + 26) * ImGuiHelpers.GlobalScale)); + ImGui.SetColumnWidth(2, 16 + (45 * ImGuiHelpers.GlobalScale)); + ImGui.SetColumnWidth(3, 14 + (26 * ImGuiHelpers.GlobalScale)); + + ImGui.Separator(); + + ImGui.Text("#"); + ImGui.NextColumn(); + ImGui.Text("Path"); + ImGui.NextColumn(); + ImGui.Text("Enabled"); + ImGui.NextColumn(); + ImGui.Text(string.Empty); + ImGui.NextColumn(); + + ImGui.Separator(); + + DevPluginLocationSettings locationToRemove = null; + + var locNumber = 1; + foreach (var devPluginLocationSetting in this.devPluginLocations) + { + var isEnabled = devPluginLocationSetting.IsEnabled; + + ImGui.PushID($"devPluginLocation_{devPluginLocationSetting.Path}"); + + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(locNumber.ToString()).X / 2)); + ImGui.Text(locNumber.ToString()); + ImGui.NextColumn(); + + ImGui.SetNextItemWidth(-1); + var path = devPluginLocationSetting.Path; + if (ImGui.InputText($"##devPluginLocationInput", ref path, 65535, ImGuiInputTextFlags.EnterReturnsTrue)) + { + var contains = this.devPluginLocations.Select(loc => loc.Path).Contains(path); + if (devPluginLocationSetting.Path == path) + { + // no change. + } + else if (contains && devPluginLocationSetting.Path != path) + { + this.devPluginLocationAddError = Loc.Localize("DalamudDevPluginLocationExists", "Location already exists."); + Task.Delay(5000).ContinueWith(t => this.devPluginLocationAddError = string.Empty); + } + else + { + devPluginLocationSetting.Path = path; + this.devPluginLocationsChanged = path != devPluginLocationSetting.Path; + } + } + + ImGui.NextColumn(); + + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 7 - (12 * ImGuiHelpers.GlobalScale)); + ImGui.Checkbox("##devPluginLocationCheck", ref isEnabled); + ImGui.NextColumn(); + + if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash)) + { + locationToRemove = devPluginLocationSetting; + } + + ImGui.PopID(); + + ImGui.NextColumn(); + ImGui.Separator(); + + devPluginLocationSetting.IsEnabled = isEnabled; + + locNumber++; + } + + if (locationToRemove != null) + { + this.devPluginLocations.Remove(locationToRemove); + this.devPluginLocationsChanged = true; + } + + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(locNumber.ToString()).X / 2)); + ImGui.Text(locNumber.ToString()); + ImGui.NextColumn(); + ImGui.SetNextItemWidth(-1); + ImGui.InputText("##devPluginLocationInput", ref this.devPluginTempLocation, 300); + ImGui.NextColumn(); + // Enabled button + ImGui.NextColumn(); + if (!string.IsNullOrEmpty(this.devPluginTempLocation) && ImGuiComponents.IconButton(FontAwesomeIcon.Plus)) + { + if (this.devPluginLocations.Any(r => string.Equals(r.Path, this.devPluginTempLocation, StringComparison.InvariantCultureIgnoreCase))) + { + this.devPluginLocationAddError = Loc.Localize("DalamudDevPluginLocationExists", "Location already exists."); + Task.Delay(5000).ContinueWith(t => this.devPluginLocationAddError = string.Empty); + } + else + { + this.devPluginLocations.Add(new DevPluginLocationSettings + { + Path = this.devPluginTempLocation.Replace("\"", string.Empty), + IsEnabled = true, + }); + this.devPluginLocationsChanged = true; + this.devPluginTempLocation = string.Empty; + } + } + + ImGui.Columns(1); + + if (!string.IsNullOrEmpty(this.devPluginLocationAddError)) + { + ImGuiHelpers.SafeTextColoredWrapped(new Vector4(1, 0, 0, 1), this.devPluginLocationAddError); + } + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/GapSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/GapSettingsEntry.cs new file mode 100644 index 000000000..bc5c2fd0a --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/GapSettingsEntry.cs @@ -0,0 +1,40 @@ +using System.Diagnostics.CodeAnalysis; + +using ImGuiNET; + +namespace Dalamud.Interface.Internal.Windows.Settings.Widgets; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")] +public sealed class GapSettingsEntry : SettingsEntry +{ + private readonly float size; + private readonly bool hr; + + public GapSettingsEntry(float size, bool hr = false) + { + this.size = size; + this.hr = hr; + this.IsValid = true; + } + + public override void Load() + { + // ignored + } + + public override void Save() + { + // ignored + } + + public override void Draw() + { + ImGuiHelpers.ScaledDummy(this.size); + + if (this.hr) + { + ImGui.Separator(); + ImGuiHelpers.ScaledDummy(this.size); + } + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/HintSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/HintSettingsEntry.cs new file mode 100644 index 000000000..d1eb43c1f --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/HintSettingsEntry.cs @@ -0,0 +1,34 @@ +using System.Diagnostics.CodeAnalysis; +using System.Numerics; + +using Dalamud.Interface.Colors; + +namespace Dalamud.Interface.Internal.Windows.Settings.Widgets; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")] +public class HintSettingsEntry : SettingsEntry +{ + private readonly string text; + private readonly Vector4 color; + + public HintSettingsEntry(string text, Vector4? color = null) + { + this.text = text; + this.color = color ?? ImGuiColors.DalamudGrey; + } + + public override void Load() + { + // ignore + } + + public override void Save() + { + // ignore + } + + public override void Draw() + { + ImGuiHelpers.SafeTextColoredWrapped(this.color, this.text); + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/LanguageChooserSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/LanguageChooserSettingsEntry.cs new file mode 100644 index 000000000..0bb373576 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/LanguageChooserSettingsEntry.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; + +using CheapLoc; +using Dalamud.Configuration.Internal; +using Dalamud.Interface.Colors; +using ImGuiNET; + +namespace Dalamud.Interface.Internal.Windows.Settings.Widgets; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")] +public sealed class LanguageChooserSettingsEntry : SettingsEntry +{ + private readonly string[] languages; + private readonly string[] locLanguages; + + private int langIndex = -1; + + public LanguageChooserSettingsEntry() + { + this.languages = Localization.ApplicableLangCodes.Prepend("en").ToArray(); + + this.Name = Loc.Localize("DalamudSettingsLanguage", "Language"); + this.IsValid = true; + this.IsVisible = true; + + try + { + var locLanguagesList = new List(); + string locLanguage; + foreach (var language in this.languages) + { + if (language != "ko") + { + locLanguage = CultureInfo.GetCultureInfo(language).NativeName; + locLanguagesList.Add(char.ToUpper(locLanguage[0]) + locLanguage[1..]); + } + else + { + locLanguagesList.Add("Korean"); + } + } + + this.locLanguages = locLanguagesList.ToArray(); + } + catch (Exception) + { + this.locLanguages = this.languages; // Languages not localized, only codes. + } + } + + public override void Load() + { + this.langIndex = Array.IndexOf(this.languages, Service.Get().EffectiveLanguage); + if (this.langIndex == -1) + this.langIndex = 0; + } + + public override void Save() + { + Service.Get().SetupWithLangCode(this.languages[this.langIndex]); + Service.Get().LanguageOverride = this.languages[this.langIndex]; + } + + public override void Draw() + { + ImGui.Text(this.Name); + ImGui.Combo("##XlLangCombo", ref this.langIndex, this.locLanguages, this.locLanguages.Length); + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsLanguageHint", "Select the language Dalamud will be displayed in.")); + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/SettingsEntry{T}.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/SettingsEntry{T}.cs new file mode 100644 index 000000000..c08eb99f6 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/SettingsEntry{T}.cs @@ -0,0 +1,174 @@ +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; + +using Dalamud.Configuration.Internal; + +using Dalamud.Interface.Colors; +using Dalamud.Utility; +using ImGuiNET; + +namespace Dalamud.Interface.Internal.Windows.Settings.Widgets; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")] +internal sealed class SettingsEntry : SettingsEntry +{ + private readonly LoadSettingDelegate load; + private readonly SaveSettingDelegate save; + private readonly Action? change; + + private object? valueBacking; + + public SettingsEntry(string name, string description, LoadSettingDelegate load, SaveSettingDelegate save, Action? change = null, Func? warning = null, Func? validity = null) + { + this.load = load; + this.save = save; + this.change = change; + this.Name = name; + this.Description = description; + this.CheckWarning = warning; + this.CheckValidity = validity; + } + + public delegate T? LoadSettingDelegate(DalamudConfiguration config); + + public delegate void SaveSettingDelegate(T? value, DalamudConfiguration config); + + public T? Value => this.valueBacking == default ? default : (T)this.valueBacking; + + public string Description { get; } + + public Func? CheckValidity { get; init; } + + public Func? CheckWarning { get; init; } + + public Func? CheckVisibility { get; init; } + + public override bool IsVisible => this.CheckVisibility?.Invoke() ?? true; + + public override void Draw() + { + Debug.Assert(this.Name != null, "this.Name != null"); + + var type = typeof(T); + + if (type == typeof(DirectoryInfo)) + { + ImGuiHelpers.SafeTextWrapped(this.Name); + + var value = this.Value as DirectoryInfo; + var nativeBuffer = value?.FullName ?? string.Empty; + + if (ImGui.InputText($"###{this.Id.ToString()}", ref nativeBuffer, 1000)) + { + this.valueBacking = !string.IsNullOrEmpty(nativeBuffer) ? new DirectoryInfo(nativeBuffer) : null; + } + } + else if (type == typeof(string)) + { + ImGuiHelpers.SafeTextWrapped(this.Name); + + var nativeBuffer = this.Value as string ?? string.Empty; + + if (ImGui.InputText($"###{this.Id.ToString()}", ref nativeBuffer, 1000)) + { + this.valueBacking = nativeBuffer; + } + } + else if (type == typeof(bool)) + { + var nativeValue = this.Value as bool? ?? false; + + if (ImGui.Checkbox($"{this.Name}###{this.Id.ToString()}", ref nativeValue)) + { + this.valueBacking = nativeValue; + this.change?.Invoke(this.Value); + } + } + else if (type.IsEnum) + { + ImGuiHelpers.SafeTextWrapped(this.Name); + + var idx = (Enum)(this.valueBacking ?? 0); + var values = Enum.GetValues(type); + var descriptions = + values.Cast().ToDictionary(x => x, x => x.GetAttribute() ?? new SettingsAnnotationAttribute(x.ToString(), string.Empty)); + + if (ImGui.BeginCombo($"###{this.Id.ToString()}", descriptions[idx].FriendlyName)) + { + foreach (Enum value in values) + { + if (ImGui.Selectable(descriptions[value].FriendlyName, idx.Equals(value))) + { + this.valueBacking = value; + } + } + + ImGui.EndCombo(); + } + } + + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey); + ImGuiHelpers.SafeTextWrapped(this.Description); + ImGui.PopStyleColor(); + + if (this.CheckValidity != null) + { + var validityMsg = this.CheckValidity.Invoke(this.Value); + this.IsValid = string.IsNullOrEmpty(validityMsg); + + if (!this.IsValid) + { + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed); + ImGui.Text(validityMsg); + ImGui.PopStyleColor(); + } + } + else + { + this.IsValid = true; + } + + var warningMessage = this.CheckWarning?.Invoke(this.Value); + + if (warningMessage != null) + { + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed); + ImGui.Text(warningMessage); + ImGui.PopStyleColor(); + } + } + + public override void Load() + { + this.valueBacking = this.load(Service.Get()); + + if (this.CheckValidity != null) + { + this.IsValid = this.CheckValidity(this.Value) == null; + } + else + { + this.IsValid = true; + } + } + + public override void Save() => this.save(this.Value, Service.Get()); +} + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")] +[AttributeUsage(AttributeTargets.Field)] +internal class SettingsAnnotationAttribute : Attribute +{ + public SettingsAnnotationAttribute(string friendlyName, string description) + { + this.FriendlyName = friendlyName; + this.Description = description; + } + + public string FriendlyName { get; set; } + + public string Description { get; set; } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs new file mode 100644 index 000000000..e410b3482 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Numerics; +using System.Threading.Tasks; + +using CheapLoc; +using Dalamud.Configuration; +using Dalamud.Configuration.Internal; +using Dalamud.Interface.Colors; +using Dalamud.Interface.Components; +using Dalamud.Plugin.Internal; +using ImGuiNET; + +namespace Dalamud.Interface.Internal.Windows.Settings.Widgets; + +[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")] +public class ThirdRepoSettingsEntry : SettingsEntry +{ + private List thirdRepoList = new(); + private bool thirdRepoListChanged; + private string thirdRepoTempUrl = string.Empty; + private string thirdRepoAddError = string.Empty; + + public override void OnClose() + { + this.thirdRepoList = + Service.Get().ThirdRepoList.Select(x => x.Clone()).ToList(); + } + + public override void Load() + { + this.thirdRepoList = + Service.Get().ThirdRepoList.Select(x => x.Clone()).ToList(); + this.thirdRepoListChanged = false; + } + + public override void Save() + { + Service.Get().ThirdRepoList = + this.thirdRepoList.Select(x => x.Clone()).ToList(); + + if (this.thirdRepoListChanged) + { + _ = Service.Get().SetPluginReposFromConfigAsync(true); + this.thirdRepoListChanged = false; + } + } + + public override void Draw() + { + ImGui.Text(Loc.Localize("DalamudSettingsCustomRepo", "Custom Plugin Repositories")); + if (this.thirdRepoListChanged) + { + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen); + ImGui.SameLine(); + ImGui.Text(Loc.Localize("DalamudSettingsChanged", "(Changed)")); + ImGui.PopStyleColor(); + } + + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingCustomRepoHint", "Add custom plugin repositories.")); + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingCustomRepoWarning", "We cannot take any responsibility for third-party plugins and repositories.")); + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingCustomRepoWarning2", "Plugins have full control over your PC, like any other program, and may cause harm or crashes.")); + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingCustomRepoWarning4", "They can delete your character, upload your family photos and burn down your house.")); + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingCustomRepoWarning3", "Please make absolutely sure that you only install third-party plugins from developers you trust.")); + + ImGuiHelpers.ScaledDummy(5); + + ImGui.Columns(4); + ImGui.SetColumnWidth(0, 18 + (5 * ImGuiHelpers.GlobalScale)); + ImGui.SetColumnWidth(1, ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X - (18 + 16 + 14) - ((5 + 45 + 26) * ImGuiHelpers.GlobalScale)); + ImGui.SetColumnWidth(2, 16 + (45 * ImGuiHelpers.GlobalScale)); + ImGui.SetColumnWidth(3, 14 + (26 * ImGuiHelpers.GlobalScale)); + + ImGui.Separator(); + + ImGui.Text("#"); + ImGui.NextColumn(); + ImGui.Text("URL"); + ImGui.NextColumn(); + ImGui.Text("Enabled"); + ImGui.NextColumn(); + ImGui.Text(string.Empty); + ImGui.NextColumn(); + + ImGui.Separator(); + + ImGui.Text("0"); + ImGui.NextColumn(); + ImGui.Text("XIVLauncher"); + ImGui.NextColumn(); + ImGui.NextColumn(); + ImGui.NextColumn(); + ImGui.Separator(); + + ThirdPartyRepoSettings repoToRemove = null; + + var repoNumber = 1; + foreach (var thirdRepoSetting in this.thirdRepoList) + { + var isEnabled = thirdRepoSetting.IsEnabled; + + ImGui.PushID($"thirdRepo_{thirdRepoSetting.Url}"); + + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(repoNumber.ToString()).X / 2)); + ImGui.Text(repoNumber.ToString()); + ImGui.NextColumn(); + + ImGui.SetNextItemWidth(-1); + var url = thirdRepoSetting.Url; + if (ImGui.InputText($"##thirdRepoInput", ref url, 65535, ImGuiInputTextFlags.EnterReturnsTrue)) + { + var contains = this.thirdRepoList.Select(repo => repo.Url).Contains(url); + if (thirdRepoSetting.Url == url) + { + // no change. + } + else if (contains && thirdRepoSetting.Url != url) + { + this.thirdRepoAddError = Loc.Localize("DalamudThirdRepoExists", "Repo already exists."); + Task.Delay(5000).ContinueWith(t => this.thirdRepoAddError = string.Empty); + } + else + { + thirdRepoSetting.Url = url; + this.thirdRepoListChanged = url != thirdRepoSetting.Url; + } + } + + ImGui.NextColumn(); + + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 7 - (12 * ImGuiHelpers.GlobalScale)); + ImGui.Checkbox("##thirdRepoCheck", ref isEnabled); + ImGui.NextColumn(); + + if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash)) + { + repoToRemove = thirdRepoSetting; + } + + ImGui.PopID(); + + ImGui.NextColumn(); + ImGui.Separator(); + + thirdRepoSetting.IsEnabled = isEnabled; + + repoNumber++; + } + + if (repoToRemove != null) + { + this.thirdRepoList.Remove(repoToRemove); + this.thirdRepoListChanged = true; + } + + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(repoNumber.ToString()).X / 2)); + ImGui.Text(repoNumber.ToString()); + ImGui.NextColumn(); + ImGui.SetNextItemWidth(-1); + ImGui.InputText("##thirdRepoUrlInput", ref this.thirdRepoTempUrl, 300); + ImGui.NextColumn(); + // Enabled button + ImGui.NextColumn(); + if (!string.IsNullOrEmpty(this.thirdRepoTempUrl) && ImGuiComponents.IconButton(FontAwesomeIcon.Plus)) + { + this.thirdRepoTempUrl = this.thirdRepoTempUrl.TrimEnd(); + if (this.thirdRepoList.Any(r => string.Equals(r.Url, this.thirdRepoTempUrl, StringComparison.InvariantCultureIgnoreCase))) + { + this.thirdRepoAddError = Loc.Localize("DalamudThirdRepoExists", "Repo already exists."); + Task.Delay(5000).ContinueWith(t => this.thirdRepoAddError = string.Empty); + } + else + { + this.thirdRepoList.Add(new ThirdPartyRepoSettings + { + Url = this.thirdRepoTempUrl, + IsEnabled = true, + }); + this.thirdRepoListChanged = true; + this.thirdRepoTempUrl = string.Empty; + } + } + + ImGui.Columns(1); + + if (!string.IsNullOrEmpty(this.thirdRepoAddError)) + { + ImGuiHelpers.SafeTextColoredWrapped(new Vector4(1, 0, 0, 1), this.thirdRepoAddError); + } + } +} diff --git a/Dalamud/Interface/Internal/Windows/SettingsWindow.cs b/Dalamud/Interface/Internal/Windows/SettingsWindow.cs deleted file mode 100644 index 72292faa3..000000000 --- a/Dalamud/Interface/Internal/Windows/SettingsWindow.cs +++ /dev/null @@ -1,982 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Numerics; -using System.Threading.Tasks; - -using CheapLoc; -using Dalamud.Configuration; -using Dalamud.Configuration.Internal; -using Dalamud.Game.Gui.Dtr; -using Dalamud.Game.Text; -using Dalamud.Interface.Colors; -using Dalamud.Interface.Components; -using Dalamud.Interface.Internal.Windows.PluginInstaller; -using Dalamud.Interface.Windowing; -using Dalamud.Plugin.Internal; -using Dalamud.Utility; -using ImGuiNET; - -namespace Dalamud.Interface.Internal.Windows; - -/// -/// The window that allows for general configuration of Dalamud itself. -/// -internal class SettingsWindow : Window -{ - private readonly string[] languages; - private readonly string[] locLanguages; - - private int langIndex; - - private XivChatType dalamudMessagesChatType; - - private bool doWaitForPluginsOnStartup; - private bool doCfTaskBarFlash; - private bool doCfChatMessage; - private bool doMbCollect; - - private float globalUiScale; - private bool doUseAxisFontsFromGame; - private float fontGamma; - private bool doToggleUiHide; - private bool doToggleUiHideDuringCutscenes; - private bool doToggleUiHideDuringGpose; - private bool doDocking; - private bool doViewport; - private bool doGamepad; - private bool doFocus; - private bool doTsm; - - private List? dtrOrder; - private List? dtrIgnore; - private int dtrSpacing; - private bool dtrSwapDirection; - - private int? pluginWaitBeforeFree; - - private List thirdRepoList; - private bool thirdRepoListChanged; - private string thirdRepoTempUrl = string.Empty; - private string thirdRepoAddError = string.Empty; - - private List devPluginLocations; - private bool devPluginLocationsChanged; - private string devPluginTempLocation = string.Empty; - private string devPluginLocationAddError = string.Empty; - - private bool printPluginsWelcomeMsg; - private bool autoUpdatePlugins; - private bool doButtonsSystemMenu; - private bool disableRmtFiltering; - - #region Experimental - - private bool doPluginTest; - - #endregion - - /// - /// Initializes a new instance of the class. - /// - public SettingsWindow() - : base(Loc.Localize("DalamudSettingsHeader", "Dalamud Settings") + "###XlSettings2", ImGuiWindowFlags.NoCollapse) - { - var configuration = Service.Get(); - - this.Size = new Vector2(740, 550); - this.SizeCondition = ImGuiCond.FirstUseEver; - - this.dalamudMessagesChatType = configuration.GeneralChatType; - - this.doWaitForPluginsOnStartup = configuration.IsResumeGameAfterPluginLoad; - this.doCfTaskBarFlash = configuration.DutyFinderTaskbarFlash; - this.doCfChatMessage = configuration.DutyFinderChatMessage; - this.doMbCollect = configuration.IsMbCollect; - - this.globalUiScale = configuration.GlobalUiScale; - this.fontGamma = configuration.FontGammaLevel; - this.doUseAxisFontsFromGame = configuration.UseAxisFontsFromGame; - this.doToggleUiHide = configuration.ToggleUiHide; - this.doToggleUiHideDuringCutscenes = configuration.ToggleUiHideDuringCutscenes; - this.doToggleUiHideDuringGpose = configuration.ToggleUiHideDuringGpose; - - this.doDocking = configuration.IsDocking; - this.doViewport = !configuration.IsDisableViewport; - this.doGamepad = configuration.IsGamepadNavigationEnabled; - this.doFocus = configuration.IsFocusManagementEnabled; - this.doTsm = configuration.ShowTsm; - - this.dtrSpacing = configuration.DtrSpacing; - this.dtrSwapDirection = configuration.DtrSwapDirection; - - this.pluginWaitBeforeFree = configuration.PluginWaitBeforeFree; - - this.doPluginTest = configuration.DoPluginTest; - this.thirdRepoList = configuration.ThirdRepoList.Select(x => x.Clone()).ToList(); - this.devPluginLocations = configuration.DevPluginLoadLocations.Select(x => x.Clone()).ToList(); - - this.printPluginsWelcomeMsg = configuration.PrintPluginsWelcomeMsg; - this.autoUpdatePlugins = configuration.AutoUpdatePlugins; - this.doButtonsSystemMenu = configuration.DoButtonsSystemMenu; - this.disableRmtFiltering = configuration.DisableRmtFiltering; - - this.languages = Localization.ApplicableLangCodes.Prepend("en").ToArray(); - this.langIndex = Array.IndexOf(this.languages, configuration.EffectiveLanguage); - if (this.langIndex == -1) - this.langIndex = 0; - - try - { - var locLanguagesList = new List(); - string locLanguage; - foreach (var language in this.languages) - { - if (language != "ko") - { - locLanguage = CultureInfo.GetCultureInfo(language).NativeName; - locLanguagesList.Add(char.ToUpper(locLanguage[0]) + locLanguage[1..]); - } - else - { - locLanguagesList.Add("Korean"); - } - } - - this.locLanguages = locLanguagesList.ToArray(); - } - catch (Exception) - { - this.locLanguages = this.languages; // Languages not localized, only codes. - } - } - - /// - public override void OnOpen() - { - this.thirdRepoListChanged = false; - this.devPluginLocationsChanged = false; - - var configuration = Service.Get(); - this.dtrOrder = configuration.DtrOrder; - this.dtrIgnore = configuration.DtrIgnore; - } - - /// - public override void OnClose() - { - var configuration = Service.Get(); - var interfaceManager = Service.Get(); - - var rebuildFont = ImGui.GetIO().FontGlobalScale != configuration.GlobalUiScale - || interfaceManager.FontGamma != configuration.FontGammaLevel - || interfaceManager.UseAxis != configuration.UseAxisFontsFromGame; - - ImGui.GetIO().FontGlobalScale = configuration.GlobalUiScale; - interfaceManager.FontGammaOverride = null; - interfaceManager.UseAxisOverride = null; - this.thirdRepoList = configuration.ThirdRepoList.Select(x => x.Clone()).ToList(); - this.devPluginLocations = configuration.DevPluginLoadLocations.Select(x => x.Clone()).ToList(); - - configuration.DtrOrder = this.dtrOrder; - configuration.DtrIgnore = this.dtrIgnore; - - if (rebuildFont) - interfaceManager.RebuildFonts(); - } - - /// - public override void Draw() - { - var windowSize = ImGui.GetWindowSize(); - ImGui.BeginChild("scrolling", new Vector2(windowSize.X - 5 - (5 * ImGuiHelpers.GlobalScale), windowSize.Y - 35 - (35 * ImGuiHelpers.GlobalScale)), false); - - if (ImGui.BeginTabBar("SetTabBar")) - { - if (ImGui.BeginTabItem(Loc.Localize("DalamudSettingsGeneral", "General") + "###settingsTabGeneral")) - { - this.DrawGeneralTab(); - ImGui.EndTabItem(); - } - - if (ImGui.BeginTabItem(Loc.Localize("DalamudSettingsVisual", "Look & Feel") + "###settingsTabVisual")) - { - this.DrawLookAndFeelTab(); - ImGui.EndTabItem(); - } - - if (ImGui.BeginTabItem(Loc.Localize("DalamudSettingsServerInfoBar", "Server Info Bar") + "###settingsTabInfoBar")) - { - this.DrawServerInfoBarTab(); - ImGui.EndTabItem(); - } - - if (ImGui.BeginTabItem(Loc.Localize("DalamudSettingsExperimental", "Experimental") + "###settingsTabExperimental")) - { - this.DrawExperimentalTab(); - ImGui.EndTabItem(); - } - - ImGui.EndTabBar(); - } - - ImGui.EndChild(); - - this.DrawSaveCloseButtons(); - } - - private void DrawGeneralTab() - { - ImGui.Text(Loc.Localize("DalamudSettingsLanguage", "Language")); - ImGui.Combo("##XlLangCombo", ref this.langIndex, this.locLanguages, this.locLanguages.Length); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsLanguageHint", "Select the language Dalamud will be displayed in.")); - - ImGuiHelpers.ScaledDummy(5); - - ImGui.Text(Loc.Localize("DalamudSettingsChannel", "General Chat Channel")); - if (ImGui.BeginCombo("##XlChatTypeCombo", this.dalamudMessagesChatType.ToString())) - { - foreach (var type in Enum.GetValues(typeof(XivChatType)).Cast()) - { - if (ImGui.Selectable(type.ToString(), type == this.dalamudMessagesChatType)) - { - this.dalamudMessagesChatType = type; - } - } - - ImGui.EndCombo(); - } - - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsChannelHint", "Select the chat channel that is to be used for general Dalamud messages.")); - - ImGuiHelpers.ScaledDummy(5); - - ImGui.Checkbox(Loc.Localize("DalamudSettingsWaitForPluginsOnStartup", "Wait for plugins before game loads"), ref this.doWaitForPluginsOnStartup); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsWaitForPluginsOnStartupHint", "Do not let the game load, until plugins are loaded.")); - - ImGui.Checkbox(Loc.Localize("DalamudSettingsFlash", "Flash FFXIV window on duty pop"), ref this.doCfTaskBarFlash); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsFlashHint", "Flash the FFXIV window in your task bar when a duty is ready.")); - - ImGui.Checkbox(Loc.Localize("DalamudSettingsDutyFinderMessage", "Chatlog message on duty pop"), ref this.doCfChatMessage); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsDutyFinderMessageHint", "Send a message in FFXIV chat when a duty is ready.")); - - ImGui.Checkbox(Loc.Localize("DalamudSettingsPrintPluginsWelcomeMsg", "Display loaded plugins in the welcome message"), ref this.printPluginsWelcomeMsg); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsPrintPluginsWelcomeMsgHint", "Display loaded plugins in FFXIV chat when logging in with a character.")); - - ImGui.Checkbox(Loc.Localize("DalamudSettingsAutoUpdatePlugins", "Auto-update plugins"), ref this.autoUpdatePlugins); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsAutoUpdatePluginsMsgHint", "Automatically update plugins when logging in with a character.")); - - ImGui.Checkbox(Loc.Localize("DalamudSettingsSystemMenu", "Dalamud buttons in system menu"), ref this.doButtonsSystemMenu); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsSystemMenuMsgHint", "Add buttons for Dalamud plugins and settings to the system menu.")); - - ImGui.Checkbox(Loc.Localize("DalamudSettingsDisableRmtFiltering", "Disable RMT Filtering"), ref this.disableRmtFiltering); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsDisableRmtFilteringMsgHint", "Disable Dalamud's built-in RMT ad filtering.")); - - ImGuiHelpers.ScaledDummy(5); - - ImGui.Checkbox(Loc.Localize("DalamudSettingDoMbCollect", "Anonymously upload market board data"), ref this.doMbCollect); - - ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey); - ImGui.TextWrapped(Loc.Localize("DalamudSettingDoMbCollectHint", "Anonymously provide data about in-game economics to Universalis when browsing the market board. This data can't be tied to you in any way and everyone benefits!")); - ImGui.PopStyleColor(); - } - - private void DrawLookAndFeelTab() - { - var interfaceManager = Service.Get(); - - ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3); - ImGui.Text(Loc.Localize("DalamudSettingsGlobalUiScale", "Global Font Scale")); - ImGui.SameLine(); - ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 3); - if (ImGui.Button("9.6pt##DalamudSettingsGlobalUiScaleReset96")) - { - this.globalUiScale = 9.6f / 12.0f; - ImGui.GetIO().FontGlobalScale = this.globalUiScale; - interfaceManager.RebuildFonts(); - } - - ImGui.SameLine(); - if (ImGui.Button("12pt##DalamudSettingsGlobalUiScaleReset12")) - { - this.globalUiScale = 1.0f; - ImGui.GetIO().FontGlobalScale = this.globalUiScale; - interfaceManager.RebuildFonts(); - } - - ImGui.SameLine(); - if (ImGui.Button("14pt##DalamudSettingsGlobalUiScaleReset14")) - { - this.globalUiScale = 14.0f / 12.0f; - ImGui.GetIO().FontGlobalScale = this.globalUiScale; - interfaceManager.RebuildFonts(); - } - - ImGui.SameLine(); - if (ImGui.Button("18pt##DalamudSettingsGlobalUiScaleReset18")) - { - this.globalUiScale = 18.0f / 12.0f; - ImGui.GetIO().FontGlobalScale = this.globalUiScale; - interfaceManager.RebuildFonts(); - } - - ImGui.SameLine(); - if (ImGui.Button("36pt##DalamudSettingsGlobalUiScaleReset36")) - { - this.globalUiScale = 36.0f / 12.0f; - ImGui.GetIO().FontGlobalScale = this.globalUiScale; - interfaceManager.RebuildFonts(); - } - - var globalUiScaleInPt = 12f * this.globalUiScale; - if (ImGui.DragFloat("##DalamudSettingsGlobalUiScaleDrag", ref globalUiScaleInPt, 0.1f, 9.6f, 36f, "%.1fpt", ImGuiSliderFlags.AlwaysClamp)) - { - this.globalUiScale = globalUiScaleInPt / 12f; - ImGui.GetIO().FontGlobalScale = this.globalUiScale; - interfaceManager.RebuildFonts(); - } - - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsGlobalUiScaleHint", "Scale text in all XIVLauncher UI elements - this is useful for 4K displays.")); - - ImGuiHelpers.ScaledDummy(10, 16); - - if (ImGui.Button(Loc.Localize("DalamudSettingsOpenStyleEditor", "Open Style Editor"))) - { - Service.Get().OpenStyleEditor(); - } - - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsStyleEditorHint", "Modify the look & feel of Dalamud windows.")); - - ImGuiHelpers.ScaledDummy(10); - - if (ImGui.Checkbox(Loc.Localize("DalamudSettingToggleAxisFonts", "Use AXIS fonts as default Dalamud font"), ref this.doUseAxisFontsFromGame)) - { - interfaceManager.UseAxisOverride = this.doUseAxisFontsFromGame; - interfaceManager.RebuildFonts(); - } - - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleUiAxisFontsHint", "Use AXIS fonts (the game's main UI fonts) as default Dalamud font.")); - - ImGuiHelpers.ScaledDummy(10); - - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleUiHideOptOutNote", "Plugins may independently opt out of the settings below.")); - - ImGuiHelpers.ScaledDummy(3); - - ImGui.Checkbox(Loc.Localize("DalamudSettingToggleUiHide", "Hide plugin UI when the game UI is toggled off"), ref this.doToggleUiHide); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleUiHideHint", "Hide any open windows by plugins when toggling the game overlay.")); - - ImGui.Checkbox(Loc.Localize("DalamudSettingToggleUiHideDuringCutscenes", "Hide plugin UI during cutscenes"), ref this.doToggleUiHideDuringCutscenes); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleUiHideDuringCutscenesHint", "Hide any open windows by plugins during cutscenes.")); - - ImGui.Checkbox(Loc.Localize("DalamudSettingToggleUiHideDuringGpose", "Hide plugin UI while gpose is active"), ref this.doToggleUiHideDuringGpose); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleUiHideDuringGposeHint", "Hide any open windows by plugins while gpose is active.")); - - ImGuiHelpers.ScaledDummy(10, 16); - - ImGui.Checkbox(Loc.Localize("DalamudSettingToggleFocusManagement", "Use escape to close Dalamud windows"), ref this.doFocus); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleFocusManagementHint", "This will cause Dalamud windows to behave like in-game windows when pressing escape.\nThey will close one after another until all are closed. May not work for all plugins.")); - - ImGui.Checkbox(Loc.Localize("DalamudSettingToggleViewports", "Enable multi-monitor windows"), ref this.doViewport); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleViewportsHint", "This will allow you move plugin windows onto other monitors.\nWill only work in Borderless Window or Windowed mode.")); - - ImGui.Checkbox(Loc.Localize("DalamudSettingToggleDocking", "Enable window docking"), ref this.doDocking); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleDockingHint", "This will allow you to fuse and tab plugin windows.")); - - ImGui.Checkbox(Loc.Localize("DalamudSettingToggleGamepadNavigation", "Control plugins via gamepad"), ref this.doGamepad); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleGamepadNavigationHint", "This will allow you to toggle between game and plugin navigation via L1+L3.\nToggle the PluginInstaller window via R3 if ImGui navigation is enabled.")); - - ImGui.Checkbox(Loc.Localize("DalamudSettingToggleTsm", "Show title screen menu"), ref this.doTsm); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleTsmHint", "This will allow you to access certain Dalamud and Plugin functionality from the title screen.")); - - ImGuiHelpers.ScaledDummy(10, 16); - ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3); - ImGui.Text(Loc.Localize("DalamudSettingsFontGamma", "Font Gamma")); - ImGui.SameLine(); - ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 3); - if (ImGui.Button(Loc.Localize("DalamudSettingsIndividualConfigResetToDefaultValue", "Reset") + "##DalamudSettingsFontGammaReset")) - { - this.fontGamma = 1.4f; - interfaceManager.FontGammaOverride = this.fontGamma; - interfaceManager.RebuildFonts(); - } - - if (ImGui.DragFloat("##DalamudSettingsFontGammaDrag", ref this.fontGamma, 0.005f, 0.3f, 3f, "%.2f", ImGuiSliderFlags.AlwaysClamp)) - { - interfaceManager.FontGammaOverride = this.fontGamma; - interfaceManager.RebuildFonts(); - } - - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsFontGammaHint", "Changes the thickness of text.")); - - ImGuiHelpers.ScaledDummy(10, 16); - } - - private void DrawServerInfoBarTab() - { - ImGui.Text(Loc.Localize("DalamudSettingServerInfoBar", "Server Info Bar configuration")); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarHint", "Plugins can put additional information into your server information bar(where world & time can be seen).\nYou can reorder and disable these here.")); - - ImGuiHelpers.ScaledDummy(10); - - var configuration = Service.Get(); - var dtrBar = Service.Get(); - - var order = configuration.DtrOrder!.Where(x => dtrBar.HasEntry(x)).ToList(); - var ignore = configuration.DtrIgnore!.Where(x => dtrBar.HasEntry(x)).ToList(); - var orderLeft = configuration.DtrOrder!.Where(x => !order.Contains(x)).ToList(); - var ignoreLeft = configuration.DtrIgnore!.Where(x => !ignore.Contains(x)).ToList(); - - if (order.Count == 0) - { - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarDidNone", "You have no plugins that use this feature.")); - } - - var isOrderChange = false; - for (var i = 0; i < order.Count; i++) - { - var title = order[i]; - - // TODO: Maybe we can also resort the rest of the bar in the future? - // var isRequired = search is Configuration.SearchSetting.Internal or Configuration.SearchSetting.MacroLinks; - - ImGui.PushFont(UiBuilder.IconFont); - - var arrowUpText = $"{FontAwesomeIcon.ArrowUp.ToIconString()}##{title}"; - if (i == 0) - { - ImGuiComponents.DisabledButton(arrowUpText); - } - else - { - if (ImGui.Button(arrowUpText)) - { - (order[i], order[i - 1]) = (order[i - 1], order[i]); - isOrderChange = true; - } - } - - ImGui.SameLine(); - - var arrowDownText = $"{FontAwesomeIcon.ArrowDown.ToIconString()}##{title}"; - if (i == order.Count - 1) - { - ImGuiComponents.DisabledButton(arrowDownText); - } - else - { - if (ImGui.Button(arrowDownText) && i != order.Count - 1) - { - (order[i], order[i + 1]) = (order[i + 1], order[i]); - isOrderChange = true; - } - } - - ImGui.PopFont(); - - ImGui.SameLine(); - - // if (isRequired) { - // ImGui.TextUnformatted($"Search in {name}"); - // } else { - - var isShown = ignore.All(x => x != title); - var nextIsShow = isShown; - if (ImGui.Checkbox($"{title}###dtrEntry{i}", ref nextIsShow) && nextIsShow != isShown) - { - if (nextIsShow) - ignore.Remove(title); - else - ignore.Add(title); - - dtrBar.MakeDirty(title); - } - - // } - } - - configuration.DtrOrder = order.Concat(orderLeft).ToList(); - configuration.DtrIgnore = ignore.Concat(ignoreLeft).ToList(); - - if (isOrderChange) - dtrBar.ApplySort(); - - ImGuiHelpers.ScaledDummy(10); - - ImGui.Text(Loc.Localize("DalamudSettingServerInfoBarSpacing", "Server Info Bar spacing")); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarSpacingHint", "Configure the amount of space between entries in the server info bar here.")); - ImGui.SliderInt("Spacing", ref this.dtrSpacing, 0, 40); - - ImGui.Text(Loc.Localize("DalamudSettingServerInfoBarDirection", "Server Info Bar direction")); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarDirectionHint", "If checked, the Server Info Bar elements will expand to the right instead of the left.")); - ImGui.Checkbox("Swap Direction", ref this.dtrSwapDirection); - } - - private void DrawExperimentalTab() - { - var configuration = Service.Get(); - var pluginManager = Service.Get(); - - var useCustomPluginWaitBeforeFree = this.pluginWaitBeforeFree.HasValue; - if (ImGui.Checkbox( - Loc.Localize("DalamudSettingsPluginCustomizeWaitTime", "Customize wait time for plugin unload"), - ref useCustomPluginWaitBeforeFree)) - { - if (!useCustomPluginWaitBeforeFree) - this.pluginWaitBeforeFree = null; - else - this.pluginWaitBeforeFree = PluginManager.PluginWaitBeforeFreeDefault; - } - - if (useCustomPluginWaitBeforeFree) - { - var waitTime = this.pluginWaitBeforeFree ?? PluginManager.PluginWaitBeforeFreeDefault; - if (ImGui.SliderInt( - "Wait time###DalamudSettingsPluginCustomizeWaitTimeSlider", - ref waitTime, - 0, - 5000)) - { - this.pluginWaitBeforeFree = waitTime; - } - } - - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsPluginCustomizeWaitTimeHint", "Configure the wait time between stopping plugin and completely unloading plugin. If you are experiencing crashes when exiting the game, try increasing this value.")); - - ImGuiHelpers.ScaledDummy(12); - - #region Plugin testing - - ImGui.Checkbox(Loc.Localize("DalamudSettingsPluginTest", "Get plugin testing builds"), ref this.doPluginTest); - ImGuiHelpers.SafeTextColoredWrapped( - ImGuiColors.DalamudGrey, - string.Format( - Loc.Localize("DalamudSettingsPluginTestHint", "Receive testing prereleases for selected plugins.\nTo opt-in to testing builds for a plugin, you have to right click it in the \"{0}\" tab of the plugin installer and select \"{1}\"."), - PluginCategoryManager.Locs.Group_Installed, - PluginInstallerWindow.Locs.PluginContext_TestingOptIn)); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingsPluginTestWarning", "Testing plugins may not have been vetted before being published. Please only enable this if you are aware of the risks.")); - - #endregion - - ImGuiHelpers.ScaledDummy(12); - - #region Hidden plugins - - if (ImGui.Button(Loc.Localize("DalamudSettingsClearHidden", "Clear hidden plugins"))) - { - configuration.HiddenPluginInternalName.Clear(); - pluginManager.RefilterPluginMasters(); - } - - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsClearHiddenHint", "Restore plugins you have previously hidden from the plugin installer.")); - - #endregion - - ImGuiHelpers.ScaledDummy(12); - - this.DrawCustomReposSection(); - - ImGuiHelpers.ScaledDummy(12); - - this.DrawDevPluginLocationsSection(); - - ImGuiHelpers.ScaledDummy(12); - - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, "Total memory used by Dalamud & Plugins: " + Util.FormatBytes(GC.GetTotalMemory(false))); - } - - private void DrawCustomReposSection() - { - ImGui.Text(Loc.Localize("DalamudSettingsCustomRepo", "Custom Plugin Repositories")); - if (this.thirdRepoListChanged) - { - ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen); - ImGui.SameLine(); - ImGui.Text(Loc.Localize("DalamudSettingsChanged", "(Changed)")); - ImGui.PopStyleColor(); - } - - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingCustomRepoHint", "Add custom plugin repositories.")); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingCustomRepoWarning", "We cannot take any responsibility for third-party plugins and repositories.")); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingCustomRepoWarning2", "Plugins have full control over your PC, like any other program, and may cause harm or crashes.")); - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingCustomRepoWarning3", "Please make absolutely sure that you only install third-party plugins from developers you trust.")); - - ImGuiHelpers.ScaledDummy(5); - - ImGui.Columns(4); - ImGui.SetColumnWidth(0, 18 + (5 * ImGuiHelpers.GlobalScale)); - ImGui.SetColumnWidth(1, ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X - (18 + 16 + 14) - ((5 + 45 + 26) * ImGuiHelpers.GlobalScale)); - ImGui.SetColumnWidth(2, 16 + (45 * ImGuiHelpers.GlobalScale)); - ImGui.SetColumnWidth(3, 14 + (26 * ImGuiHelpers.GlobalScale)); - - ImGui.Separator(); - - ImGui.Text("#"); - ImGui.NextColumn(); - ImGui.Text("URL"); - ImGui.NextColumn(); - ImGui.Text("Enabled"); - ImGui.NextColumn(); - ImGui.Text(string.Empty); - ImGui.NextColumn(); - - ImGui.Separator(); - - ImGui.Text("0"); - ImGui.NextColumn(); - ImGui.Text("XIVLauncher"); - ImGui.NextColumn(); - ImGui.NextColumn(); - ImGui.NextColumn(); - ImGui.Separator(); - - ThirdPartyRepoSettings repoToRemove = null; - - var repoNumber = 1; - foreach (var thirdRepoSetting in this.thirdRepoList) - { - var isEnabled = thirdRepoSetting.IsEnabled; - - ImGui.PushID($"thirdRepo_{thirdRepoSetting.Url}"); - - ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(repoNumber.ToString()).X / 2)); - ImGui.Text(repoNumber.ToString()); - ImGui.NextColumn(); - - ImGui.SetNextItemWidth(-1); - var url = thirdRepoSetting.Url; - if (ImGui.InputText($"##thirdRepoInput", ref url, 65535, ImGuiInputTextFlags.EnterReturnsTrue)) - { - var contains = this.thirdRepoList.Select(repo => repo.Url).Contains(url); - if (thirdRepoSetting.Url == url) - { - // no change. - } - else if (contains && thirdRepoSetting.Url != url) - { - this.thirdRepoAddError = Loc.Localize("DalamudThirdRepoExists", "Repo already exists."); - Task.Delay(5000).ContinueWith(t => this.thirdRepoAddError = string.Empty); - } - else - { - thirdRepoSetting.Url = url; - this.thirdRepoListChanged = url != thirdRepoSetting.Url; - } - } - - ImGui.NextColumn(); - - ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 7 - (12 * ImGuiHelpers.GlobalScale)); - ImGui.Checkbox("##thirdRepoCheck", ref isEnabled); - ImGui.NextColumn(); - - if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash)) - { - repoToRemove = thirdRepoSetting; - } - - ImGui.PopID(); - - ImGui.NextColumn(); - ImGui.Separator(); - - thirdRepoSetting.IsEnabled = isEnabled; - - repoNumber++; - } - - if (repoToRemove != null) - { - this.thirdRepoList.Remove(repoToRemove); - this.thirdRepoListChanged = true; - } - - ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(repoNumber.ToString()).X / 2)); - ImGui.Text(repoNumber.ToString()); - ImGui.NextColumn(); - ImGui.SetNextItemWidth(-1); - ImGui.InputText("##thirdRepoUrlInput", ref this.thirdRepoTempUrl, 300); - ImGui.NextColumn(); - // Enabled button - ImGui.NextColumn(); - if (!string.IsNullOrEmpty(this.thirdRepoTempUrl) && ImGuiComponents.IconButton(FontAwesomeIcon.Plus)) - { - this.thirdRepoTempUrl = this.thirdRepoTempUrl.TrimEnd(); - if (this.thirdRepoList.Any(r => string.Equals(r.Url, this.thirdRepoTempUrl, StringComparison.InvariantCultureIgnoreCase))) - { - this.thirdRepoAddError = Loc.Localize("DalamudThirdRepoExists", "Repo already exists."); - Task.Delay(5000).ContinueWith(t => this.thirdRepoAddError = string.Empty); - } - else - { - this.thirdRepoList.Add(new ThirdPartyRepoSettings - { - Url = this.thirdRepoTempUrl, - IsEnabled = true, - }); - this.thirdRepoListChanged = true; - this.thirdRepoTempUrl = string.Empty; - } - } - - ImGui.Columns(1); - - if (!string.IsNullOrEmpty(this.thirdRepoAddError)) - { - ImGuiHelpers.SafeTextColoredWrapped(new Vector4(1, 0, 0, 1), this.thirdRepoAddError); - } - } - - private void DrawDevPluginLocationsSection() - { - ImGui.Text(Loc.Localize("DalamudSettingsDevPluginLocation", "Dev Plugin Locations")); - if (this.devPluginLocationsChanged) - { - ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen); - ImGui.SameLine(); - ImGui.Text(Loc.Localize("DalamudSettingsChanged", "(Changed)")); - ImGui.PopStyleColor(); - } - - ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsDevPluginLocationsHint", "Add additional dev plugin load locations.\nThese can be either the directory or DLL path.")); - - ImGuiHelpers.ScaledDummy(5); - - ImGui.Columns(4); - ImGui.SetColumnWidth(0, 18 + (5 * ImGuiHelpers.GlobalScale)); - ImGui.SetColumnWidth(1, ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X - (18 + 16 + 14) - ((5 + 45 + 26) * ImGuiHelpers.GlobalScale)); - ImGui.SetColumnWidth(2, 16 + (45 * ImGuiHelpers.GlobalScale)); - ImGui.SetColumnWidth(3, 14 + (26 * ImGuiHelpers.GlobalScale)); - - ImGui.Separator(); - - ImGui.Text("#"); - ImGui.NextColumn(); - ImGui.Text("Path"); - ImGui.NextColumn(); - ImGui.Text("Enabled"); - ImGui.NextColumn(); - ImGui.Text(string.Empty); - ImGui.NextColumn(); - - ImGui.Separator(); - - DevPluginLocationSettings locationToRemove = null; - - var locNumber = 1; - foreach (var devPluginLocationSetting in this.devPluginLocations) - { - var isEnabled = devPluginLocationSetting.IsEnabled; - - ImGui.PushID($"devPluginLocation_{devPluginLocationSetting.Path}"); - - ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(locNumber.ToString()).X / 2)); - ImGui.Text(locNumber.ToString()); - ImGui.NextColumn(); - - ImGui.SetNextItemWidth(-1); - var path = devPluginLocationSetting.Path; - if (ImGui.InputText($"##devPluginLocationInput", ref path, 65535, ImGuiInputTextFlags.EnterReturnsTrue)) - { - var contains = this.devPluginLocations.Select(loc => loc.Path).Contains(path); - if (devPluginLocationSetting.Path == path) - { - // no change. - } - else if (contains && devPluginLocationSetting.Path != path) - { - this.devPluginLocationAddError = Loc.Localize("DalamudDevPluginLocationExists", "Location already exists."); - Task.Delay(5000).ContinueWith(t => this.devPluginLocationAddError = string.Empty); - } - else - { - devPluginLocationSetting.Path = path; - this.devPluginLocationsChanged = path != devPluginLocationSetting.Path; - } - } - - ImGui.NextColumn(); - - ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 7 - (12 * ImGuiHelpers.GlobalScale)); - ImGui.Checkbox("##devPluginLocationCheck", ref isEnabled); - ImGui.NextColumn(); - - if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash)) - { - locationToRemove = devPluginLocationSetting; - } - - ImGui.PopID(); - - ImGui.NextColumn(); - ImGui.Separator(); - - devPluginLocationSetting.IsEnabled = isEnabled; - - locNumber++; - } - - if (locationToRemove != null) - { - this.devPluginLocations.Remove(locationToRemove); - this.devPluginLocationsChanged = true; - } - - ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(locNumber.ToString()).X / 2)); - ImGui.Text(locNumber.ToString()); - ImGui.NextColumn(); - ImGui.SetNextItemWidth(-1); - ImGui.InputText("##devPluginLocationInput", ref this.devPluginTempLocation, 300); - ImGui.NextColumn(); - // Enabled button - ImGui.NextColumn(); - if (!string.IsNullOrEmpty(this.devPluginTempLocation) && ImGuiComponents.IconButton(FontAwesomeIcon.Plus)) - { - if (this.devPluginLocations.Any(r => string.Equals(r.Path, this.devPluginTempLocation, StringComparison.InvariantCultureIgnoreCase))) - { - this.devPluginLocationAddError = Loc.Localize("DalamudDevPluginLocationExists", "Location already exists."); - Task.Delay(5000).ContinueWith(t => this.devPluginLocationAddError = string.Empty); - } - else - { - this.devPluginLocations.Add(new DevPluginLocationSettings - { - Path = this.devPluginTempLocation.Replace("\"", string.Empty), - IsEnabled = true, - }); - this.devPluginLocationsChanged = true; - this.devPluginTempLocation = string.Empty; - } - } - - ImGui.Columns(1); - - if (!string.IsNullOrEmpty(this.devPluginLocationAddError)) - { - ImGuiHelpers.SafeTextColoredWrapped(new Vector4(1, 0, 0, 1), this.devPluginLocationAddError); - } - } - - private void DrawSaveCloseButtons() - { - var buttonSave = false; - var buttonClose = false; - - var pluginManager = Service.Get(); - - if (ImGui.Button(Loc.Localize("Save", "Save"))) - buttonSave = true; - - ImGui.SameLine(); - - if (ImGui.Button(Loc.Localize("Close", "Close"))) - buttonClose = true; - - ImGui.SameLine(); - - if (ImGui.Button(Loc.Localize("SaveAndClose", "Save and Close"))) - buttonSave = buttonClose = true; - - if (buttonSave) - { - this.Save(); - - if (this.thirdRepoListChanged) - { - _ = pluginManager.SetPluginReposFromConfigAsync(true); - this.thirdRepoListChanged = false; - } - - if (this.devPluginLocationsChanged) - { - pluginManager.ScanDevPlugins(); - this.devPluginLocationsChanged = false; - } - } - - if (buttonClose) - { - this.IsOpen = false; - } - } - - private void Save() - { - var configuration = Service.Get(); - var localization = Service.Get(); - - localization.SetupWithLangCode(this.languages[this.langIndex]); - configuration.LanguageOverride = this.languages[this.langIndex]; - - configuration.GeneralChatType = this.dalamudMessagesChatType; - - configuration.IsResumeGameAfterPluginLoad = this.doWaitForPluginsOnStartup; - configuration.DutyFinderTaskbarFlash = this.doCfTaskBarFlash; - configuration.DutyFinderChatMessage = this.doCfChatMessage; - configuration.IsMbCollect = this.doMbCollect; - - configuration.GlobalUiScale = this.globalUiScale; - configuration.ToggleUiHide = this.doToggleUiHide; - configuration.ToggleUiHideDuringCutscenes = this.doToggleUiHideDuringCutscenes; - configuration.ToggleUiHideDuringGpose = this.doToggleUiHideDuringGpose; - - configuration.IsDocking = this.doDocking; - configuration.IsGamepadNavigationEnabled = this.doGamepad; - configuration.IsFocusManagementEnabled = this.doFocus; - configuration.ShowTsm = this.doTsm; - - configuration.UseAxisFontsFromGame = this.doUseAxisFontsFromGame; - configuration.FontGammaLevel = this.fontGamma; - - // This is applied every frame in InterfaceManager::CheckViewportState() - configuration.IsDisableViewport = !this.doViewport; - - // Apply docking flag - if (!configuration.IsDocking) - { - ImGui.GetIO().ConfigFlags &= ~ImGuiConfigFlags.DockingEnable; - } - else - { - ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.DockingEnable; - } - - // NOTE (Chiv) Toggle gamepad navigation via setting - if (!configuration.IsGamepadNavigationEnabled) - { - ImGui.GetIO().BackendFlags &= ~ImGuiBackendFlags.HasGamepad; - ImGui.GetIO().ConfigFlags &= ~ImGuiConfigFlags.NavEnableSetMousePos; - - var di = Service.Get(); - di.CloseGamepadModeNotifierWindow(); - } - else - { - ImGui.GetIO().BackendFlags |= ImGuiBackendFlags.HasGamepad; - ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.NavEnableSetMousePos; - } - - this.dtrOrder = configuration.DtrOrder; - this.dtrIgnore = configuration.DtrIgnore; - - configuration.DtrSpacing = this.dtrSpacing; - configuration.DtrSwapDirection = this.dtrSwapDirection; - - configuration.PluginWaitBeforeFree = this.pluginWaitBeforeFree; - - configuration.DoPluginTest = this.doPluginTest; - configuration.ThirdRepoList = this.thirdRepoList.Select(x => x.Clone()).ToList(); - configuration.DevPluginLoadLocations = this.devPluginLocations.Select(x => x.Clone()).ToList(); - - configuration.PrintPluginsWelcomeMsg = this.printPluginsWelcomeMsg; - configuration.AutoUpdatePlugins = this.autoUpdatePlugins; - configuration.DoButtonsSystemMenu = this.doButtonsSystemMenu; - configuration.DisableRmtFiltering = this.disableRmtFiltering; - - configuration.QueueSave(); - - _ = Service.Get().ReloadPluginMastersAsync(); - Service.Get().RebuildFonts(); - } -} diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs index 06cb52845..e03db5e91 100644 --- a/Dalamud/Plugin/Internal/PluginManager.cs +++ b/Dalamud/Plugin/Internal/PluginManager.cs @@ -43,7 +43,7 @@ internal partial class PluginManager : IDisposable, IServiceType /// /// Default time to wait between plugin unload and plugin assembly unload. /// - public const int PluginWaitBeforeFreeDefault = 500; + public const int PluginWaitBeforeFreeDefault = 1000; // upped from 500ms, seems more stable private const string DevPluginsDisclaimerFilename = "DONT_USE_THIS_FOLDER.txt"; diff --git a/Dalamud/Utility/EnumExtensions.cs b/Dalamud/Utility/EnumExtensions.cs index 8868e4c1f..b4c58d95c 100644 --- a/Dalamud/Utility/EnumExtensions.cs +++ b/Dalamud/Utility/EnumExtensions.cs @@ -14,12 +14,15 @@ public static class EnumExtensions /// The type of attribute to get. /// The enum value that has an attached attribute. /// The attached attribute, if any. - public static TAttribute GetAttribute(this Enum value) + public static TAttribute? GetAttribute(this Enum value) where TAttribute : Attribute { var type = value.GetType(); var name = Enum.GetName(type, value); - return type.GetField(name) // I prefer to get attributes this way + if (name.IsNullOrEmpty()) + return null; + + return type.GetField(name)? .GetCustomAttributes(false) .OfType() .SingleOrDefault(); From 24f42ccbe95e1437ae659ceac6b28fdd81c9627a Mon Sep 17 00:00:00 2001 From: goaaats Date: Sat, 7 Jan 2023 15:16:54 +0100 Subject: [PATCH 25/51] deps: update FFXIVClientStructs --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index aa8cf2754..2152fef49 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit aa8cf2754333fcc98b3e10c0fc9461e4de22a49d +Subproject commit 2152fef49d3a5574121c23c45e70d0c24647a025 From dbeb99bb6372efd53d835348c3654c6cdca4737e Mon Sep 17 00:00:00 2001 From: goaaats Date: Sat, 7 Jan 2023 15:27:29 +0100 Subject: [PATCH 26/51] fix: invalidate third repo list when state is toggled --- .../Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs index e410b3482..37876811f 100644 --- a/Dalamud/Interface/Internal/Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs @@ -131,7 +131,11 @@ public class ThirdRepoSettingsEntry : SettingsEntry ImGui.NextColumn(); ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 7 - (12 * ImGuiHelpers.GlobalScale)); - ImGui.Checkbox("##thirdRepoCheck", ref isEnabled); + if (ImGui.Checkbox("##thirdRepoCheck", ref isEnabled)) + { + this.thirdRepoListChanged = true; + } + ImGui.NextColumn(); if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash)) From 43dd798abc313b745065ad530e6ad3a188a35692 Mon Sep 17 00:00:00 2001 From: Aireil <33433913+Aireil@users.noreply.github.com> Date: Sat, 7 Jan 2023 17:21:00 +0100 Subject: [PATCH 27/51] feat: add search bar in stat window for hooks --- .../Internal/Windows/PluginStatWindow.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs b/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs index 5ea7f3db6..e5e8b90e7 100644 --- a/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs @@ -10,7 +10,9 @@ using Dalamud.Interface.Internal.Notifications; using Dalamud.Interface.Windowing; using Dalamud.Plugin.Internal; using Dalamud.Plugin.Internal.Types; +using Dalamud.Utility; using ImGuiNET; +using Serilog; namespace Dalamud.Interface.Internal.Windows; @@ -20,6 +22,7 @@ namespace Dalamud.Interface.Internal.Windows; internal class PluginStatWindow : Window { private bool showDalamudHooks; + private string hookSearchText = string.Empty; /// /// Initializes a new instance of the class. @@ -211,6 +214,12 @@ internal class PluginStatWindow : Window { ImGui.Checkbox("Show Dalamud Hooks", ref this.showDalamudHooks); + ImGui.InputTextWithHint( + "###PluginStatWindow_HookSearch", + "Search", + ref this.hookSearchText, + 500); + if (ImGui.BeginTable( "##PluginStatsHooks", 4, @@ -238,6 +247,13 @@ internal class PluginStatWindow : Window if (!this.showDalamudHooks && trackedHook.Assembly == Assembly.GetExecutingAssembly()) continue; + if (!this.hookSearchText.IsNullOrEmpty()) + { + if ((trackedHook.Delegate.Target == null || !trackedHook.Delegate.Target.ToString().Contains(this.hookSearchText, StringComparison.OrdinalIgnoreCase)) + && !trackedHook.Delegate.Method.Name.Contains(this.hookSearchText, StringComparison.OrdinalIgnoreCase)) + continue; + } + ImGui.TableNextRow(); ImGui.TableNextColumn(); @@ -281,7 +297,7 @@ internal class PluginStatWindow : Window } catch (Exception ex) { - ImGui.Text(ex.Message); + Log.Error(ex, "Error drawing hooks in plugin stats"); } } From 568f750d595363b100fab5d7e2ce35cc5fb8ccd1 Mon Sep 17 00:00:00 2001 From: goaaats Date: Sat, 7 Jan 2023 22:29:16 +0100 Subject: [PATCH 28/51] fix: don't attempt to load orphaned plugins --- Dalamud/Plugin/Internal/PluginManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs index e03db5e91..d882af084 100644 --- a/Dalamud/Plugin/Internal/PluginManager.cs +++ b/Dalamud/Plugin/Internal/PluginManager.cs @@ -866,13 +866,13 @@ Thanks and have fun!"; { try { - if (!plugin.IsDisabled) + if (!plugin.IsDisabled && !plugin.IsOrphaned) { await plugin.LoadAsync(reason); } else { - Log.Verbose($"{name} was disabled"); + Log.Verbose($"{name} not loaded, disabled:{plugin.IsDisabled} orphaned:{plugin.IsOrphaned}"); } } catch (InvalidPluginException) From 21b8adff4dcfb111d0ab084f647d191995036d99 Mon Sep 17 00:00:00 2001 From: goaaats Date: Sat, 7 Jan 2023 23:23:16 +0100 Subject: [PATCH 29/51] fix: allow control for orphaned plugins --- .../Windows/PluginInstaller/PluginInstallerWindow.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs index 4fcdf83ac..973720aeb 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs @@ -1465,7 +1465,7 @@ internal class PluginInstallerWindow : Window, IDisposable return ready; } - private bool DrawPluginCollapsingHeader(string label, LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty, bool trouble, bool updateAvailable, bool isNew, bool installableOutdated, Action drawContextMenuAction, int index) + private bool DrawPluginCollapsingHeader(string label, LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty, bool trouble, bool updateAvailable, bool isNew, bool installableOutdated, bool isOrphan, Action drawContextMenuAction, int index) { ImGui.Separator(); @@ -1536,7 +1536,7 @@ internal class PluginInstallerWindow : Window, IDisposable if (updateAvailable) ImGui.Image(this.imageCache.UpdateIcon.ImGuiHandle, iconSize); - else if (trouble && !pluginDisabled) + else if ((trouble && !pluginDisabled) || isOrphan) ImGui.Image(this.imageCache.TroubleIcon.ImGuiHandle, iconSize); else if (installableOutdated) ImGui.Image(this.imageCache.OutdatedInstallableIcon.ImGuiHandle, iconSize); @@ -1737,7 +1737,7 @@ internal class PluginInstallerWindow : Window, IDisposable ImGui.PushID($"available{index}{manifest.InternalName}"); var isThirdParty = manifest.SourceRepo.IsThirdParty; - if (this.DrawPluginCollapsingHeader(label, null, manifest, isThirdParty, false, false, !wasSeen, isOutdated, () => this.DrawAvailablePluginContextMenu(manifest), index)) + if (this.DrawPluginCollapsingHeader(label, null, manifest, isThirdParty, false, false, !wasSeen, isOutdated, false, () => this.DrawAvailablePluginContextMenu(manifest), index)) { if (!wasSeen) configuration.SeenPluginInternalName.Add(manifest.InternalName); @@ -1987,7 +1987,7 @@ internal class PluginInstallerWindow : Window, IDisposable ImGui.PushID($"installed{index}{plugin.Manifest.InternalName}"); var hasChangelog = !plugin.Manifest.Changelog.IsNullOrEmpty(); - if (this.DrawPluginCollapsingHeader(label, plugin, plugin.Manifest, plugin.Manifest.IsThirdParty, trouble, availablePluginUpdate != default, false, false, () => this.DrawInstalledPluginContextMenu(plugin, testingOptIn), index)) + if (this.DrawPluginCollapsingHeader(label, plugin, plugin.Manifest, plugin.Manifest.IsThirdParty, trouble, availablePluginUpdate != default, false, false, plugin.IsOrphaned, () => this.DrawInstalledPluginContextMenu(plugin, testingOptIn), index)) { if (!this.WasPluginSeen(plugin.Manifest.InternalName)) configuration.SeenPluginInternalName.Add(plugin.Manifest.InternalName); @@ -2188,7 +2188,8 @@ internal class PluginInstallerWindow : Window, IDisposable disabled = disabled || (plugin.IsOutdated && !pluginManager.LoadAllApiLevels) || plugin.IsBanned; // Disable everything if the plugin is orphaned - disabled = disabled || plugin.IsOrphaned; + // Control will immediately be disabled once the plugin is disabled + disabled = disabled || (plugin.IsOrphaned && !plugin.IsLoaded); // Disable everything if the plugin failed to load disabled = disabled || plugin.State == PluginState.LoadError || plugin.State == PluginState.DependencyResolutionFailed; From fb9aeae1bcb45af9f7487b11496072e994874300 Mon Sep 17 00:00:00 2001 From: Kaz Wolfe Date: Sat, 7 Jan 2023 14:33:41 -0800 Subject: [PATCH 30/51] Fix a bad docstring that squicked through --- Dalamud/Plugin/DalamudPluginInterface.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Plugin/DalamudPluginInterface.cs b/Dalamud/Plugin/DalamudPluginInterface.cs index 7e39a85d7..6524c90a8 100644 --- a/Dalamud/Plugin/DalamudPluginInterface.cs +++ b/Dalamud/Plugin/DalamudPluginInterface.cs @@ -42,7 +42,7 @@ public sealed class DalamudPluginInterface : IDisposable /// Location of the assembly. /// The reason the plugin was loaded. /// A value indicating whether this is a dev plugin. - /// The repository from which the plugin is installed. + /// The local manifest for this plugin. internal DalamudPluginInterface(string pluginName, FileInfo assemblyLocation, PluginLoadReason reason, bool isDev, LocalPluginManifest manifest) { var configuration = Service.Get(); From e3cbc4dc8cdf2dac115b854de3c7b58d6a764bcf Mon Sep 17 00:00:00 2001 From: goaaats Date: Sat, 7 Jan 2023 23:48:20 +0100 Subject: [PATCH 31/51] feat: note if a plugin is no longer being serviced --- .../PluginInstaller/PluginInstallerWindow.cs | 25 +++++++++++++++++ Dalamud/Plugin/Internal/Types/LocalPlugin.cs | 28 +++++++++++++++++-- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs index 973720aeb..c603f8054 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs @@ -1600,6 +1600,18 @@ internal class PluginInstallerWindow : Window, IDisposable ImGui.TextWrapped(Locs.PluginBody_Orphaned); ImGui.PopStyleColor(); } + else if (plugin is { IsDecommissioned: true } && !plugin.Manifest.IsThirdParty) + { + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed); + ImGui.TextWrapped(Locs.PluginBody_NoServiceOfficial); + ImGui.PopStyleColor(); + } + else if (plugin is { IsDecommissioned: true } && plugin.Manifest.IsThirdParty) + { + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed); + ImGui.TextWrapped(Locs.PluginBody_NoServiceThird); + ImGui.PopStyleColor(); + } else if (plugin != null && !plugin.CheckPolicy()) { ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed); @@ -1978,6 +1990,13 @@ internal class PluginInstallerWindow : Window, IDisposable trouble = true; } + // Out of service + if (plugin.IsDecommissioned) + { + label += Locs.PluginTitleMod_NoService; + trouble = true; + } + // Scheduled for deletion if (plugin.Manifest.ScheduledForDeletion) { @@ -2875,6 +2894,8 @@ internal class PluginInstallerWindow : Window, IDisposable public static string PluginTitleMod_Disabled => Loc.Localize("InstallerDisabled", " (disabled)"); + public static string PluginTitleMod_NoService => Loc.Localize("InstallerNoService", " (decommissioned)"); + public static string PluginTitleMod_Unloaded => Loc.Localize("InstallerUnloaded", " (unloaded)"); public static string PluginTitleMod_HasUpdate => Loc.Localize("InstallerHasUpdate", " (has update)"); @@ -2943,6 +2964,10 @@ internal class PluginInstallerWindow : Window, IDisposable public static string PluginBody_Orphaned => Loc.Localize("InstallerOrphanedPluginBody ", "This plugin's source repository is no longer available. You may need to reinstall it from its repository, or re-add the repository."); + public static string PluginBody_NoServiceOfficial => Loc.Localize("InstallerNoServiceOfficialPluginBody", "This plugin is no longer being maintained. It will still work, but there will be no further updates and you can't reinstall it."); + + public static string PluginBody_NoServiceThird => Loc.Localize("InstallerNoServiceThirdPluginBody", "This plugin is no longer being serviced by its source repo. You may have to look for an updated version in another repo."); + public static string PluginBody_LoadFailed => Loc.Localize("InstallerLoadFailedPluginBody ", "This plugin failed to load. Please contact the author for more information."); public static string PluginBody_Banned => Loc.Localize("InstallerBannedPluginBody ", "This plugin was automatically disabled due to incompatibilities and is not available at the moment. Please wait for it to be updated by its author."); diff --git a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs index b49f5799c..807dd0bef 100644 --- a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs +++ b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs @@ -220,8 +220,13 @@ internal class LocalPlugin : IDisposable /// public bool IsOrphaned => !this.IsDev && !this.Manifest.InstalledFromUrl.IsNullOrEmpty() && // TODO(api8): Remove this, all plugins will have a proper flag - Service.Get().Repos.All(x => x.PluginMasterUrl != this.Manifest.InstalledFromUrl) && - this.Manifest.InstalledFromUrl != LocalPluginManifest.FlagMainRepo; + this.GetSourceRepository() == null; + + /// + /// Gets a value indicating whether or not this plugin is serviced(repo still exists, but plugin no longer does). + /// + public bool IsDecommissioned => !this.IsDev && + this.GetSourceRepository()?.PluginMaster?.FirstOrDefault(x => x.InternalName == this.Manifest.InternalName) == null; /// /// Gets a value indicating whether this plugin has been banned. @@ -638,6 +643,25 @@ internal class LocalPlugin : IDisposable } } + /// + /// Get the repository this plugin was installed from. + /// + /// The plugin repository this plugin was installed from, or null if it is no longer there or if the plugin is a dev plugin. + public PluginRepository? GetSourceRepository() + { + if (this.IsDev) + return null; + + var repos = Service.Get().Repos; + return repos.FirstOrDefault(x => + { + if (!x.IsThirdParty && !this.Manifest.IsThirdParty) + return true; + + return x.PluginMasterUrl == this.Manifest.InstalledFromUrl; + }); + } + private static void SetupLoaderConfig(LoaderConfig config) { config.IsUnloadable = true; From fc9c94299f7544004a796383ffea39969ce5f2d2 Mon Sep 17 00:00:00 2001 From: goaaats Date: Sun, 8 Jan 2023 00:04:33 +0100 Subject: [PATCH 32/51] fix: only fire Login event when PC GO is available --- Dalamud/Game/ClientState/ClientState.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dalamud/Game/ClientState/ClientState.cs b/Dalamud/Game/ClientState/ClientState.cs index 491d2aeae..cacb42c0a 100644 --- a/Dalamud/Game/ClientState/ClientState.cs +++ b/Dalamud/Game/ClientState/ClientState.cs @@ -63,7 +63,7 @@ public sealed class ClientState : IDisposable, IServiceType public event EventHandler TerritoryChanged; /// - /// Event that fires when a character is logging in. + /// Event that fires when a character is logging in, and the local character object is available. /// public event EventHandler Login; @@ -167,7 +167,7 @@ public sealed class ClientState : IDisposable, IServiceType if (condition == null || gameGui == null || data == null) return; - if (condition.Any() && this.lastConditionNone == true) + if (condition.Any() && this.lastConditionNone == true && this.LocalPlayer != null) { Log.Debug("Is login"); this.lastConditionNone = false; From 31a4f895a094458770e44862f5516fd134781dfe Mon Sep 17 00:00:00 2001 From: goaaats Date: Sun, 8 Jan 2023 00:13:56 +0100 Subject: [PATCH 33/51] fix: don't show plugin as decommissioned when orphaned --- .../Internal/Windows/PluginInstaller/PluginInstallerWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs index c603f8054..c6297ffa1 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs @@ -1991,7 +1991,7 @@ internal class PluginInstallerWindow : Window, IDisposable } // Out of service - if (plugin.IsDecommissioned) + if (plugin.IsDecommissioned && !plugin.IsOrphaned) { label += Locs.PluginTitleMod_NoService; trouble = true; From c7215c25a59dca399c25598e9a11fe5d4cc933c8 Mon Sep 17 00:00:00 2001 From: goaaats Date: Sun, 8 Jan 2023 00:14:26 +0100 Subject: [PATCH 34/51] feat: don't close settings window when saving, if shift is held --- .../Internal/Windows/Settings/SettingsWindow.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs b/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs index 24423b48c..519a0dc58 100644 --- a/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs +++ b/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs @@ -170,14 +170,19 @@ internal class SettingsWindow : Window { this.Save(); - this.IsOpen = false; + if (!ImGui.IsKeyDown(ImGuiKey.ModShift)) + this.IsOpen = false; } ImGui.PopStyleVar(); ImGui.PopFont(); if (ImGui.IsItemHovered()) - ImGui.SetTooltip(Loc.Localize("DalamudSettingsSaveAndExit", "Save changes and close")); + { + ImGui.SetTooltip(!ImGui.IsKeyDown(ImGuiKey.ModShift) + ? Loc.Localize("DalamudSettingsSaveAndExit", "Save changes and close") + : Loc.Localize("DalamudSettingsSaveAndExit", "Save changes")); + } if (invalid) ImGui.EndDisabled(); From bb6109db450be45dcda22c7f77fb3acf4e52d950 Mon Sep 17 00:00:00 2001 From: goaaats Date: Sun, 8 Jan 2023 00:15:04 +0100 Subject: [PATCH 35/51] fix: TSM not interactable when animating --- .../Internal/Windows/TitleScreenMenuWindow.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs b/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs index 3d8fadb53..284559a4e 100644 --- a/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs +++ b/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs @@ -134,7 +134,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable pos = finalPos; } - this.DrawEntry(entry, moveEasing.IsRunning && i != 0, true, i == 0, true); + this.DrawEntry(entry, moveEasing.IsRunning && i != 0, true, i == 0, true, moveEasing.IsDone); var cursor = ImGui.GetCursorPos(); cursor.Y = (float)pos; @@ -177,7 +177,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable var finalPos = (i + 1) * this.shadeTexture.Height * scale; - this.DrawEntry(entry, i != 0, true, i == 0, false); + this.DrawEntry(entry, i != 0, true, i == 0, false, false); var cursor = ImGui.GetCursorPos(); cursor.Y = finalPos; @@ -205,7 +205,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable case State.Hide: { - if (this.DrawEntry(tsm.Entries[0], true, false, true, true)) + if (this.DrawEntry(tsm.Entries[0], true, false, true, true, false)) { this.state = State.Show; } @@ -228,7 +228,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable } private bool DrawEntry( - TitleScreenMenu.TitleScreenMenuEntry entry, bool inhibitFadeout, bool showText, bool isFirst, bool overrideAlpha) + TitleScreenMenu.TitleScreenMenuEntry entry, bool inhibitFadeout, bool showText, bool isFirst, bool overrideAlpha, bool interactable) { InterfaceManager.SpecialGlyphRequest fontHandle; if (this.specialGlyphRequests.TryGetValue(entry.Name, out fontHandle) && fontHandle.Size != TargetFontSizePx) @@ -271,7 +271,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable } var isClick = ImGui.IsItemClicked(); - if (isClick) + if (isClick && interactable) { entry.Trigger(); } From 6ea7273e04b84fdd1b282178bc6594ebf4df335d Mon Sep 17 00:00:00 2001 From: goaaats Date: Sun, 8 Jan 2023 00:32:24 +0100 Subject: [PATCH 36/51] feat: give dev plugins more leeway regarding unload errors --- .../PluginInstaller/PluginInstallerWindow.cs | 2 +- .../Plugin/Internal/Types/LocalDevPlugin.cs | 10 +++++++-- Dalamud/Plugin/Internal/Types/LocalPlugin.cs | 22 ++++++++++++++----- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs index c6297ffa1..17358646e 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs @@ -2222,7 +2222,7 @@ internal class PluginInstallerWindow : Window, IDisposable StyleModelV1.DalamudStandard.Push(); - if (plugin.State == PluginState.UnloadError) + if (plugin.State == PluginState.UnloadError && !plugin.IsDev) { ImGuiComponents.DisabledButton(FontAwesomeIcon.Frown); diff --git a/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs index cb051fa59..498bea874 100644 --- a/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs +++ b/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs @@ -138,9 +138,9 @@ internal class LocalDevPlugin : LocalPlugin, IDisposable return; } - if (this.State != PluginState.Loaded && this.State != PluginState.LoadError) + if (this.State != PluginState.Loaded && this.State != PluginState.LoadError && this.State != PluginState.UnloadError) { - Log.Debug($"Skipping reload of {this.Name}, state ({this.State}) is not {PluginState.Loaded} nor {PluginState.LoadError}."); + Log.Debug($"Skipping reload of {this.Name}, state ({this.State}) is not {PluginState.Loaded}, {PluginState.LoadError} or {PluginState.UnloadError}."); return; } @@ -148,6 +148,12 @@ internal class LocalDevPlugin : LocalPlugin, IDisposable try { + if (this.State == PluginState.UnloadError) + { + Log.Warning($"{this.Manifest.Author}: TAKE CARE!!! You need to fix your unload error, and restart the game - your plugin might be in an inconsistent state."); + Log.Warning("Reloading anyway, as this is a dev plugin, but you might encounter unexpected results."); + } + await this.ReloadAsync(); notificationManager.AddNotification($"The DevPlugin '{this.Name} was reloaded successfully.", "Plugin reloaded!", NotificationType.Success); } diff --git a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs index 807dd0bef..2961aae9c 100644 --- a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs +++ b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs @@ -15,7 +15,6 @@ using Dalamud.Logging.Internal; using Dalamud.Plugin.Internal.Exceptions; using Dalamud.Plugin.Internal.Loader; using Dalamud.Utility; -using Dalamud.Utility.Signatures; namespace Dalamud.Plugin.Internal.Types; @@ -305,8 +304,13 @@ internal class LocalPlugin : IDisposable throw new InvalidPluginOperationException( $"Unable to load {this.Name}, load previously faulted, unload first"); case PluginState.UnloadError: - throw new InvalidPluginOperationException( + if (!this.IsDev) + { + throw new InvalidPluginOperationException( $"Unable to load {this.Name}, unload previously faulted, restart Dalamud"); + } + + break; case PluginState.Unloaded: break; case PluginState.Loading: @@ -471,8 +475,13 @@ internal class LocalPlugin : IDisposable case PluginState.Unloaded: throw new InvalidPluginOperationException($"Unable to unload {this.Name}, already unloaded"); case PluginState.UnloadError: - throw new InvalidPluginOperationException( - $"Unable to unload {this.Name}, unload previously faulted, restart Dalamud"); + if (!this.IsDev) + { + throw new InvalidPluginOperationException( + $"Unable to unload {this.Name}, unload previously faulted, restart Dalamud"); + } + + break; case PluginState.Loaded: case PluginState.LoadError: break; @@ -531,7 +540,10 @@ internal class LocalPlugin : IDisposable /// A task. public async Task ReloadAsync() { - await this.UnloadAsync(true); + // Don't unload if we're a dev plugin and have an unload error, this is a bad idea but whatever + if (this.IsDev && this.State != PluginState.UnloadError) + await this.UnloadAsync(true); + await this.LoadAsync(PluginLoadReason.Reload, true); } From e153e73e77c67e539a35e31b3aa6bb9f299dd8fa Mon Sep 17 00:00:00 2001 From: goaaats Date: Sun, 8 Jan 2023 00:35:04 +0100 Subject: [PATCH 37/51] fix: don't show punchline if a plugin is troublesome --- .../Internal/Windows/PluginInstaller/PluginInstallerWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs index 17358646e..f305a722d 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs @@ -1629,7 +1629,7 @@ internal class PluginInstallerWindow : Window, IDisposable ImGui.SetCursorPosX(cursor.X); // Description - if (plugin is null or { IsOutdated: false, IsBanned: false }) + if (plugin is null or { IsOutdated: false, IsBanned: false } && !trouble) { if (!string.IsNullOrWhiteSpace(manifest.Punchline)) { From e225f4df0ec3b225a40dfcf69e7bd0154e5376d1 Mon Sep 17 00:00:00 2001 From: goaaats Date: Sun, 8 Jan 2023 00:47:15 +0100 Subject: [PATCH 38/51] fix: consistent CLI arg naming scheme --- Dalamud.Injector/EntryPoint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud.Injector/EntryPoint.cs b/Dalamud.Injector/EntryPoint.cs index 11da5e6c0..d1ada5f64 100644 --- a/Dalamud.Injector/EntryPoint.cs +++ b/Dalamud.Injector/EntryPoint.cs @@ -332,7 +332,7 @@ namespace Dalamud.Injector startInfo.BootVehEnabled = true; startInfo.BootVehFull = args.Contains("--veh-full"); startInfo.NoLoadPlugins = args.Contains("--no-plugin"); - startInfo.NoLoadThirdPartyPlugins = args.Contains("--no-third-plugin"); + startInfo.NoLoadThirdPartyPlugins = args.Contains("--no-3rd-plugin"); // startInfo.BootUnhookDlls = new List() { "kernel32.dll", "ntdll.dll", "user32.dll" }; startInfo.CrashHandlerShow = args.Contains("--crash-handler-console"); From 2849613d79fed52b063cc7cae2365f3f5d9a373a Mon Sep 17 00:00:00 2001 From: goat Date: Mon, 9 Jan 2023 00:20:38 +0100 Subject: [PATCH 39/51] fix: don't throw when enabling an already enabled plugin (needed for orphans) --- Dalamud/Plugin/Internal/Types/LocalPlugin.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs index 2961aae9c..3c5405830 100644 --- a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs +++ b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs @@ -570,8 +570,11 @@ internal class LocalPlugin : IDisposable throw new ArgumentOutOfRangeException(this.State.ToString()); } - if (!this.Manifest.Disabled) - throw new InvalidPluginOperationException($"Unable to enable {this.Name}, not disabled"); + // NOTE(goat): This is inconsequential, and we do have situations where a plugin can end up enabled but not loaded: + // Orphaned plugins can have their repo added back, but may not have been loaded at boot and may still be enabled. + // We don't want to disable orphaned plugins when they are orphaned so this is how it's going to be. + // if (!this.Manifest.Disabled) + // throw new InvalidPluginOperationException($"Unable to enable {this.Name}, not disabled"); this.Manifest.Disabled = false; this.Manifest.ScheduledForDeletion = false; From 8505b8c7ef6b88ee2d554c0f18d68375d00800e3 Mon Sep 17 00:00:00 2001 From: aers Date: Sun, 8 Jan 2023 18:01:45 -0800 Subject: [PATCH 40/51] Update ClientStructs to the .NET 7 version --- Dalamud.sln | 2 +- Dalamud/ServiceManager.cs | 4 ++-- lib/FFXIVClientStructs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dalamud.sln b/Dalamud.sln index a618f1156..b3817d45e 100644 --- a/Dalamud.sln +++ b/Dalamud.sln @@ -32,7 +32,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dalamud.CorePlugin", "Dalam EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFXIVClientStructs", "lib\FFXIVClientStructs\FFXIVClientStructs\FFXIVClientStructs.csproj", "{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFXIVClientStructs.Generators", "lib\FFXIVClientStructs\FFXIVClientStructs.Generators\FFXIVClientStructs.Generators.csproj", "{05AB2F46-268B-4915-806F-DDF813E2D59D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFXIVClientStructs.InteropSourceGenerators", "lib\FFXIVClientStructs\FFXIVClientStructs.InteropSourceGenerators\FFXIVClientStructs.InteropSourceGenerators.csproj", "{05AB2F46-268B-4915-806F-DDF813E2D59D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DalamudCrashHandler", "DalamudCrashHandler\DalamudCrashHandler.vcxproj", "{317A264C-920B-44A1-8A34-F3A6827B0705}" EndProject diff --git a/Dalamud/ServiceManager.cs b/Dalamud/ServiceManager.cs index a7eb7457d..d49fe5aa6 100644 --- a/Dalamud/ServiceManager.cs +++ b/Dalamud/ServiceManager.cs @@ -68,8 +68,8 @@ internal static class ServiceManager using (Timings.Start("CS Resolver Init")) { - FFXIVClientStructs.Resolver.InitializeParallel( - new FileInfo(Path.Combine(cacheDir.FullName, $"{startInfo.GameVersion}_cs.json"))); + FFXIVClientStructs.Interop.Resolver.GetInstance.SetupSearchSpace(Service.Get().SearchBase, new FileInfo(Path.Combine(cacheDir.FullName, $"{startInfo.GameVersion}_cs.json"))); + FFXIVClientStructs.Interop.Resolver.GetInstance.Resolve(); } } diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index 2152fef49..80c299eb8 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit 2152fef49d3a5574121c23c45e70d0c24647a025 +Subproject commit 80c299eb8083fd8117fed5d025106806236c0eab From 4eef155d0c86a0a6817374549dd882edb9b5f117 Mon Sep 17 00:00:00 2001 From: MidoriKami <9083275+MidoriKami@users.noreply.github.com> Date: Sun, 8 Jan 2023 18:28:13 -0800 Subject: [PATCH 41/51] GameGui.cs GetAddonByName use default index of 1 to reflect most common usage of function. --- Dalamud/Game/Gui/GameGui.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Game/Gui/GameGui.cs b/Dalamud/Game/Gui/GameGui.cs index 18f59c75a..301f7a634 100644 --- a/Dalamud/Game/Gui/GameGui.cs +++ b/Dalamud/Game/Gui/GameGui.cs @@ -323,7 +323,7 @@ public sealed unsafe class GameGui : IDisposable, IServiceType /// Name of addon to find. /// Index of addon to find (1-indexed). /// IntPtr.Zero if unable to find UI, otherwise IntPtr pointing to the start of the addon. - public unsafe IntPtr GetAddonByName(string name, int index) + public unsafe IntPtr GetAddonByName(string name, int index = 1) { var atkStage = FFXIVClientStructs.FFXIV.Component.GUI.AtkStage.GetSingleton(); if (atkStage == null) From dda94cc4c80c788da70f994e9ea061203c5eee6e Mon Sep 17 00:00:00 2001 From: aers Date: Sun, 8 Jan 2023 18:59:34 -0800 Subject: [PATCH 42/51] Update FFXIVClientStructs --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index 80c299eb8..b942f41dd 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit 80c299eb8083fd8117fed5d025106806236c0eab +Subproject commit b942f41dd81be189877184d4dfcfeea8ee3ad517 From a3a0450079ee73069583985191e9e7ce8f8db21b Mon Sep 17 00:00:00 2001 From: aers Date: Sun, 8 Jan 2023 22:23:05 -0800 Subject: [PATCH 43/51] Update FFXIVClientStructs --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index b942f41dd..2ee44846c 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit b942f41dd81be189877184d4dfcfeea8ee3ad517 +Subproject commit 2ee44846c128b1a6a2983cec3b49712a1035a0e1 From a0383a80a998d3cd47ee277214c10bd4193c9493 Mon Sep 17 00:00:00 2001 From: Harmony <19539165+BitsOfAByte@users.noreply.github.com> Date: Mon, 28 Nov 2022 21:16:11 +0000 Subject: [PATCH 44/51] feat(interface): don't allow object table in PvP --- Dalamud/Interface/Internal/Windows/DataWindow.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Dalamud/Interface/Internal/Windows/DataWindow.cs b/Dalamud/Interface/Internal/Windows/DataWindow.cs index fcfe3edd8..cab595544 100644 --- a/Dalamud/Interface/Internal/Windows/DataWindow.cs +++ b/Dalamud/Interface/Internal/Windows/DataWindow.cs @@ -450,6 +450,10 @@ internal class DataWindow : Window { ImGui.TextUnformatted("LocalPlayer null."); } + else if (clientState.IsPvPExcludingDen) + { + ImGui.TextUnformatted("Cannot access object table while in PvP."); + } else { stateString += $"ObjectTableLen: {objectTable.Length}\n"; From d6d50a5c3f6dcfeec0c86800440f73a5bdc99146 Mon Sep 17 00:00:00 2001 From: Cara Date: Tue, 10 Jan 2023 18:31:56 +1030 Subject: [PATCH 45/51] Update ClientStateAddressResolver.ConditionFlags --- Dalamud/Game/ClientState/ClientStateAddressResolver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Game/ClientState/ClientStateAddressResolver.cs b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs index 98d3bc6dd..da2975f8b 100644 --- a/Dalamud/Game/ClientState/ClientStateAddressResolver.cs +++ b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs @@ -114,7 +114,7 @@ public sealed class ClientStateAddressResolver : BaseAddressResolver this.KeyboardState = sig.ScanText("48 8D 0C 85 ?? ?? ?? ?? 8B 04 31 85 C2 0F 85") + 0x4; this.KeyboardStateIndexArray = sig.ScanText("0F B6 94 33 ?? ?? ?? ?? 84 D2") + 0x4; - this.ConditionFlags = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? BA ?? ?? ?? ?? E8 ?? ?? ?? ?? B0 01 48 83 C4 30"); + this.ConditionFlags = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? 41 8D 50 77 E8 ?? ?? ?? ?? 48 8B 5C 24"); this.TargetManager = sig.GetStaticAddressFromSig("48 8B 05 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? FF 50 ?? 48 85 DB"); From 57df8bd50f8f1d0ef5ab8b92988836eb499dd716 Mon Sep 17 00:00:00 2001 From: Cara Date: Tue, 10 Jan 2023 18:33:09 +1030 Subject: [PATCH 46/51] Update FlyTextGuiAddressResolver.CreateFlyText --- Dalamud/Game/Gui/FlyText/FlyTextGuiAddressResolver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Game/Gui/FlyText/FlyTextGuiAddressResolver.cs b/Dalamud/Game/Gui/FlyText/FlyTextGuiAddressResolver.cs index f608c7d77..588177032 100644 --- a/Dalamud/Game/Gui/FlyText/FlyTextGuiAddressResolver.cs +++ b/Dalamud/Game/Gui/FlyText/FlyTextGuiAddressResolver.cs @@ -26,6 +26,6 @@ public class FlyTextGuiAddressResolver : BaseAddressResolver protected override void Setup64Bit(SigScanner sig) { this.AddFlyText = sig.ScanText("E8 ?? ?? ?? ?? FF C7 41 D1 C7"); - this.CreateFlyText = sig.ScanText("48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 40 48 63 FA"); + this.CreateFlyText = sig.ScanText("40 53 55 41 56 48 83 EC 40 48 63 EA"); } } From 4a74c19b6f9c4f5c5f27773aa61b63867acf28ec Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 10 Jan 2023 06:25:00 -0500 Subject: [PATCH 47/51] fix: update flytext API for damage type icon feature --- Dalamud/Game/Gui/FlyText/FlyTextGui.cs | 27 ++++++++++++------- .../Interface/Internal/Windows/DataWindow.cs | 5 +++- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Dalamud/Game/Gui/FlyText/FlyTextGui.cs b/Dalamud/Game/Gui/FlyText/FlyTextGui.cs index cf5ca68ad..c69f6cb9c 100644 --- a/Dalamud/Game/Gui/FlyText/FlyTextGui.cs +++ b/Dalamud/Game/Gui/FlyText/FlyTextGui.cs @@ -49,6 +49,7 @@ public sealed class FlyTextGui : IDisposable, IServiceType /// Text2 passed to the native flytext function. /// Color passed to the native flytext function. Changes flytext color. /// Icon ID passed to the native flytext function. Only displays with select FlyTextKind. + /// Damage Type Icon ID passed to the native flytext function. Displayed next to damage values to denote damage type. /// 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. /// Whether this flytext has been handled. If a subscriber sets this to true, the FlyText will not appear. @@ -60,6 +61,7 @@ public sealed class FlyTextGui : IDisposable, IServiceType ref SeString text2, ref uint color, ref uint icon, + ref uint damageTypeIcon, ref float yOffset, ref bool handled); @@ -74,6 +76,7 @@ public sealed class FlyTextGui : IDisposable, IServiceType IntPtr text2, uint color, uint icon, + uint damageTypeIcon, IntPtr text1, float yOffset); @@ -120,7 +123,8 @@ public sealed class FlyTextGui : IDisposable, IServiceType /// Text2 passed to the native flytext function. /// Color passed to the native flytext function. Changes flytext color. /// Icon ID passed to the native flytext function. Only displays with select FlyTextKind. - public unsafe void AddFlyText(FlyTextKind kind, uint actorIndex, uint val1, uint val2, SeString text1, SeString text2, uint color, uint icon) + /// Damage Type Icon ID passed to the native flytext function. Displayed next to damage values to denote damage type. + 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 var numIndex = 28; @@ -134,7 +138,7 @@ public sealed class FlyTextGui : IDisposable, IServiceType return; var ui = (FFXIVClientStructs.FFXIV.Client.UI.UIModule*)gameGui.GetUIModule(); - var flytext = gameGui.GetAddonByName("_FlyText", 1); + var flytext = gameGui.GetAddonByName("_FlyText"); if (ui == null || flytext == IntPtr.Zero) return; @@ -149,11 +153,12 @@ public sealed class FlyTextGui : IDisposable, IServiceType numArray->IntArray[numOffset + 1] = (int)kind; numArray->IntArray[numOffset + 2] = unchecked((int)val1); numArray->IntArray[numOffset + 3] = unchecked((int)val2); - numArray->IntArray[numOffset + 4] = 5; // Unknown - numArray->IntArray[numOffset + 5] = unchecked((int)color); - numArray->IntArray[numOffset + 6] = unchecked((int)icon); - numArray->IntArray[numOffset + 7] = 0; // Unknown - numArray->IntArray[numOffset + 8] = 0; // Unknown, has something to do with yOffset + numArray->IntArray[numOffset + 4] = unchecked((int)damageTypeIcon); // Icons for damage type + numArray->IntArray[numOffset + 5] = 5; // Unknown + numArray->IntArray[numOffset + 6] = unchecked((int)color); + numArray->IntArray[numOffset + 7] = unchecked((int)icon); + numArray->IntArray[numOffset + 8] = 0; // Unknown + numArray->IntArray[numOffset + 9] = 0; // Unknown, has something to do with yOffset fixed (byte* pText1 = text1.Encode()) { @@ -200,6 +205,7 @@ public sealed class FlyTextGui : IDisposable, IServiceType IntPtr text2, uint color, uint icon, + uint damageTypeIcon, IntPtr text1, float yOffset) { @@ -217,13 +223,14 @@ public sealed class FlyTextGui : IDisposable, IServiceType var tmpText2 = text2 == IntPtr.Zero ? string.Empty : MemoryHelper.ReadSeStringNullTerminated(text2); var tmpColor = color; var tmpIcon = icon; + var tmpDamageTypeIcon = damageTypeIcon; var tmpYOffset = yOffset; var cmpText1 = tmpText1.ToString(); var cmpText2 = tmpText2.ToString(); Log.Verbose($"[FlyText] Called with addonFlyText({addonFlyText.ToInt64():X}) " + - $"kind({kind}) val1({val1}) val2({val2}) " + + $"kind({kind}) val1({val1}) val2({val2}) damageTypeIcon({damageTypeIcon}) " + $"text1({text1.ToInt64():X}, \"{tmpText1}\") text2({text2.ToInt64():X}, \"{tmpText2}\") " + $"color({color:X}) icon({icon}) yOffset({yOffset})"); Log.Verbose("[FlyText] Calling flytext events!"); @@ -235,6 +242,7 @@ public sealed class FlyTextGui : IDisposable, IServiceType ref tmpText2, ref tmpColor, ref tmpIcon, + ref tmpDamageTypeIcon, ref tmpYOffset, ref handled); @@ -262,7 +270,7 @@ public sealed class FlyTextGui : IDisposable, IServiceType if (!dirty) { Log.Verbose("[FlyText] Calling flytext with original args."); - return this.createFlyTextHook.Original(addonFlyText, kind, val1, val2, text2, color, icon, text1, yOffset); + return this.createFlyTextHook.Original(addonFlyText, kind, val1, val2, text2, color, icon, damageTypeIcon, text1, yOffset); } var terminated1 = Terminate(tmpText1.Encode()); @@ -281,6 +289,7 @@ public sealed class FlyTextGui : IDisposable, IServiceType pText2, tmpColor, tmpIcon, + tmpDamageTypeIcon, pText1, tmpYOffset); diff --git a/Dalamud/Interface/Internal/Windows/DataWindow.cs b/Dalamud/Interface/Internal/Windows/DataWindow.cs index fcfe3edd8..2cfcdefc4 100644 --- a/Dalamud/Interface/Internal/Windows/DataWindow.cs +++ b/Dalamud/Interface/Internal/Windows/DataWindow.cs @@ -99,6 +99,7 @@ internal class DataWindow : Window private string flyText1 = string.Empty; private string flyText2 = string.Empty; private int flyIcon; + private int flyDmgIcon; private Vector4 flyColor = new(1, 0, 0, 1); // ImGui fields @@ -1157,6 +1158,7 @@ internal class DataWindow : Window ImGui.InputInt("Val2", ref this.flyVal2); ImGui.InputInt("Icon ID", ref this.flyIcon); + ImGui.InputInt("Damage Icon ID", ref this.flyDmgIcon); ImGui.ColorEdit4("Color", ref this.flyColor); ImGui.InputInt("Actor Index", ref this.flyActor); var sendColor = ImGui.ColorConvertFloat4ToU32(this.flyColor); @@ -1171,7 +1173,8 @@ internal class DataWindow : Window this.flyText1, this.flyText2, sendColor, - unchecked((uint)this.flyIcon)); + unchecked((uint)this.flyIcon), + unchecked((uint)this.flyDmgIcon)); } } From 251359abe92ed805f1163f1a9da28a0aa4f891cb Mon Sep 17 00:00:00 2001 From: NotNite Date: Tue, 10 Jan 2023 10:48:30 -0500 Subject: [PATCH 48/51] Bump plugin API level to 8 --- Dalamud/Plugin/Internal/PluginManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs index d882af084..3dd5de1a9 100644 --- a/Dalamud/Plugin/Internal/PluginManager.cs +++ b/Dalamud/Plugin/Internal/PluginManager.cs @@ -38,7 +38,7 @@ internal partial class PluginManager : IDisposable, IServiceType /// /// The current Dalamud API level, used to handle breaking changes. Only plugins with this level will be loaded. /// - public const int DalamudApiLevel = 7; + public const int DalamudApiLevel = 8; /// /// Default time to wait between plugin unload and plugin assembly unload. From b9f2736bf99fd38acc120f0e4c6457209ce4a7f6 Mon Sep 17 00:00:00 2001 From: goat Date: Tue, 10 Jan 2023 19:09:27 +0100 Subject: [PATCH 49/51] deps: upgrade CheapLoc to 1.1.7 --- Dalamud/Dalamud.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index e1c09aeef..ea770d495 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -63,7 +63,7 @@ - + From 857096eac5d78667d8e733618c6045586dd02be8 Mon Sep 17 00:00:00 2001 From: goat Date: Tue, 10 Jan 2023 19:10:40 +0100 Subject: [PATCH 50/51] deps: upgrade FFXIVClientStructs --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index 2ee44846c..e166ae024 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit 2ee44846c128b1a6a2983cec3b49712a1035a0e1 +Subproject commit e166ae024d04dc18b115405c8788cbcaf8d4c0f0 From 0861320ae0261208bb3dc0958f1f11690e2fde91 Mon Sep 17 00:00:00 2001 From: goat Date: Tue, 10 Jan 2023 19:25:28 +0100 Subject: [PATCH 51/51] deps: upgrade CheapLoc to 1.1.8 --- Dalamud/Dalamud.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index ea770d495..215252cb5 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -63,7 +63,7 @@ - +