Merge remote-tracking branch 'origin/master' into fools23

This commit is contained in:
NotNite 2023-03-31 13:18:04 -04:00
commit e710c43ab5
No known key found for this signature in database
GPG key ID: BD91A5402CCEB08A
26 changed files with 367 additions and 183 deletions

View file

@ -1,19 +0,0 @@
name: Remove old artifacts
on:
schedule:
# Every day at 1am
- cron: '0 1 * * *'
jobs:
remove-old-artifacts:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Remove old artifacts
uses: c-hive/gha-remove-artifacts@v1.2.0
with:
age: '1 month'
skip-tags: true
skip-recent: 3

View file

@ -71,6 +71,7 @@ jobs:
} }
$newVersion = [System.IO.File]::ReadAllText("$(Get-Location)\scratch\TEMP_gitver.txt") $newVersion = [System.IO.File]::ReadAllText("$(Get-Location)\scratch\TEMP_gitver.txt")
$revision = [System.IO.File]::ReadAllText("$(Get-Location)\scratch\revision.txt")
Remove-Item -Force -Recurse .\scratch Remove-Item -Force -Recurse .\scratch
if (Test-Path -Path $branchName) { if (Test-Path -Path $branchName) {
@ -82,6 +83,7 @@ jobs:
Move-Item -Force ".\canary.zip" ".\${branchName}\latest.zip" Move-Item -Force ".\canary.zip" ".\${branchName}\latest.zip"
$versionData.AssemblyVersion = $newVersion $versionData.AssemblyVersion = $newVersion
$versionData | add-member -Force -Name "GitSha" $newVersion -MemberType NoteProperty $versionData | add-member -Force -Name "GitSha" $newVersion -MemberType NoteProperty
$versionData | add-member -Force -Name "Revision" $revision -MemberType NoteProperty
$versionData | ConvertTo-Json -Compress | Out-File ".\${branchName}\version" $versionData | ConvertTo-Json -Compress | Out-File ".\${branchName}\version"
} }

View file

@ -6,6 +6,8 @@
#include "hooks.h" #include "hooks.h"
#include "logging.h" #include "logging.h"
#include "utils.h" #include "utils.h"
#include <iphlpapi.h>
#include <icmpapi.h>
template<typename T> template<typename T>
static std::span<T> assume_nonempty_span(std::span<T> t, const char* descr) { static std::span<T> assume_nonempty_span(std::span<T> t, const char* descr) {
@ -554,6 +556,40 @@ void xivfixes::clr_failfast_hijack(bool bApply)
} }
} }
void xivfixes::prevent_icmphandle_crashes(bool bApply) {
static const char* LogTag = "[xivfixes:prevent_icmphandle_crashes]";
static std::optional<hooks::import_hook<decltype(IcmpCloseHandle)>> s_hookIcmpCloseHandle;
if (bApply) {
if (!g_startInfo.BootEnabledGameFixes.contains("prevent_icmphandle_crashes")) {
logging::I("{} Turned off via environment variable.", LogTag);
return;
}
s_hookIcmpCloseHandle.emplace("iphlpapi.dll!IcmpCloseHandle (import, prevent_icmphandle_crashes)", "iphlpapi.dll", "IcmpCloseHandle", 0);
s_hookIcmpCloseHandle->set_detour([](HANDLE IcmpHandle) noexcept {
// this is exactly how windows behaves, however calling IcmpCloseHandle with
// an invalid handle will segfault on wine...
if (IcmpHandle == INVALID_HANDLE_VALUE) {
logging::W("{} IcmpCloseHandle was called with INVALID_HANDLE_VALUE", LogTag);
return FALSE;
}
return s_hookIcmpCloseHandle->call_original(IcmpHandle);
});
logging::I("{} Enable", LogTag);
}
else {
if (s_hookIcmpCloseHandle) {
logging::I("{} Disable", LogTag);
s_hookIcmpCloseHandle.reset();
}
}
}
void xivfixes::apply_all(bool bApply) { void xivfixes::apply_all(bool bApply) {
for (const auto& [taskName, taskFunction] : std::initializer_list<std::pair<const char*, void(*)(bool)>> for (const auto& [taskName, taskFunction] : std::initializer_list<std::pair<const char*, void(*)(bool)>>
{ {
@ -562,7 +598,8 @@ void xivfixes::apply_all(bool bApply) {
{ "disable_game_openprocess_access_check", &disable_game_openprocess_access_check }, { "disable_game_openprocess_access_check", &disable_game_openprocess_access_check },
{ "redirect_openprocess", &redirect_openprocess }, { "redirect_openprocess", &redirect_openprocess },
{ "backup_userdata_save", &backup_userdata_save }, { "backup_userdata_save", &backup_userdata_save },
{ "clr_failfast_hijack", &clr_failfast_hijack } { "clr_failfast_hijack", &clr_failfast_hijack },
{ "prevent_icmphandle_crashes", &prevent_icmphandle_crashes }
} }
) { ) {
try { try {

View file

@ -7,6 +7,7 @@ namespace xivfixes {
void redirect_openprocess(bool bApply); void redirect_openprocess(bool bApply);
void backup_userdata_save(bool bApply); void backup_userdata_save(bool bApply);
void clr_failfast_hijack(bool bApply); void clr_failfast_hijack(bool bApply);
void prevent_icmphandle_crashes(bool bApply);
void apply_all(bool bApply); void apply_all(bool bApply);
} }

View file

@ -325,7 +325,7 @@ namespace Dalamud.Injector
startInfo.BootShowConsole = args.Contains("--console"); startInfo.BootShowConsole = args.Contains("--console");
startInfo.BootEnableEtw = args.Contains("--etw"); startInfo.BootEnableEtw = args.Contains("--etw");
startInfo.BootLogPath = GetLogPath("dalamud.boot", startInfo.LogName); startInfo.BootLogPath = GetLogPath("dalamud.boot", startInfo.LogName);
startInfo.BootEnabledGameFixes = new List<string> { "prevent_devicechange_crashes", "disable_game_openprocess_access_check", "redirect_openprocess", "backup_userdata_save", "clr_failfast_hijack" }; startInfo.BootEnabledGameFixes = new List<string> { "prevent_devicechange_crashes", "disable_game_openprocess_access_check", "redirect_openprocess", "backup_userdata_save", "clr_failfast_hijack", "prevent_icmphandle_crashes" };
startInfo.BootDotnetOpenProcessHookMode = 0; startInfo.BootDotnetOpenProcessHookMode = 0;
startInfo.BootWaitMessageBox |= args.Contains("--msgbox1") ? 1 : 0; startInfo.BootWaitMessageBox |= args.Contains("--msgbox1") ? 1 : 0;
startInfo.BootWaitMessageBox |= args.Contains("--msgbox2") ? 2 : 0; startInfo.BootWaitMessageBox |= args.Contains("--msgbox2") ? 2 : 0;

View file

@ -244,6 +244,11 @@ internal sealed class DalamudConfiguration : IServiceType
/// </summary> /// </summary>
public int? PluginWaitBeforeFree { get; set; } public int? PluginWaitBeforeFree { get; set; }
/// <summary>
/// Gets or sets a value indicating whether or not crashes during shutdown should be reported.
/// </summary>
public bool ReportShutdownCrashes { get; set; }
/// <summary> /// <summary>
/// Gets or sets a list of saved styles. /// Gets or sets a list of saved styles.
/// </summary> /// </summary>

View file

@ -11,6 +11,7 @@ using Dalamud.Game.Gui.Internal;
using Dalamud.Interface.Internal; using Dalamud.Interface.Internal;
using Dalamud.Plugin.Internal; using Dalamud.Plugin.Internal;
using Dalamud.Utility; using Dalamud.Utility;
using PInvoke;
using Serilog; using Serilog;
#if DEBUG #if DEBUG
@ -103,6 +104,16 @@ internal sealed class Dalamud : IServiceType
public void Unload() public void Unload()
{ {
Log.Information("Trigger unload"); Log.Information("Trigger unload");
var reportCrashesSetting = Service<DalamudConfiguration>.GetNullable()?.ReportShutdownCrashes ?? true;
var pmHasDevPlugins = Service<PluginManager>.GetNullable()?.InstalledPlugins.Any(x => x.IsDev) ?? false;
if (!reportCrashesSetting && !pmHasDevPlugins)
{
// Leaking on purpose for now
var attribs = Kernel32.SECURITY_ATTRIBUTES.Create();
Kernel32.CreateMutex(attribs, false, "DALAMUD_CRASHES_NO_MORE");
}
this.unloadSignal.Set(); this.unloadSignal.Set();
} }

View file

@ -8,7 +8,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Label="Feature"> <PropertyGroup Label="Feature">
<DalamudVersion>7.4.7.5</DalamudVersion> <DalamudVersion>7.4.9.0</DalamudVersion>
<Description>XIV Launcher addon framework</Description> <Description>XIV Launcher addon framework</Description>
<AssemblyVersion>$(DalamudVersion)</AssemblyVersion> <AssemblyVersion>$(DalamudVersion)</AssemblyVersion>
<Version>$(DalamudVersion)</Version> <Version>$(DalamudVersion)</Version>
@ -124,6 +124,7 @@
<PropertyGroup> <PropertyGroup>
<!-- Needed temporarily for CI --> <!-- Needed temporarily for CI -->
<TempVerFile>$(OutputPath)TEMP_gitver.txt</TempVerFile> <TempVerFile>$(OutputPath)TEMP_gitver.txt</TempVerFile>
<DalamudRevisionFile>$(OutputPath)revision.txt</DalamudRevisionFile>
</PropertyGroup> </PropertyGroup>
<Target Name="GetGitCommitCount" BeforeTargets="WriteGitHash" Condition="'$(CommitCount)'==''"> <Target Name="GetGitCommitCount" BeforeTargets="WriteGitHash" Condition="'$(CommitCount)'==''">
@ -135,6 +136,8 @@
<PropertyGroup> <PropertyGroup>
<CommitCount>$([System.Text.RegularExpressions.Regex]::Replace($(DalamudGitCommitCount), @"\t|\n|\r", ""))</CommitCount> <CommitCount>$([System.Text.RegularExpressions.Regex]::Replace($(DalamudGitCommitCount), @"\t|\n|\r", ""))</CommitCount>
</PropertyGroup> </PropertyGroup>
<Exec Command="echo|set /P =&quot;$(CommitCount)&quot; &gt; $(DalamudRevisionFile)" IgnoreExitCode="true" />
</Target> </Target>
<Target Name="GetGitHash" BeforeTargets="WriteGitHash" Condition="'$(BuildHash)'=='' And '$(Configuration)'=='Release'"> <Target Name="GetGitHash" BeforeTargets="WriteGitHash" Condition="'$(BuildHash)'=='' And '$(Configuration)'=='Release'">

View file

@ -23,6 +23,7 @@ namespace Dalamud.Game.ClientState;
[ServiceManager.BlockingEarlyLoadedService] [ServiceManager.BlockingEarlyLoadedService]
public sealed class ClientState : IDisposable, IServiceType public sealed class ClientState : IDisposable, IServiceType
{ {
private readonly GameLifecycle lifecycle;
private readonly ClientStateAddressResolver address; private readonly ClientStateAddressResolver address;
private readonly Hook<SetupTerritoryTypeDelegate> setupTerritoryTypeHook; private readonly Hook<SetupTerritoryTypeDelegate> setupTerritoryTypeHook;
@ -36,8 +37,9 @@ public sealed class ClientState : IDisposable, IServiceType
private bool lastFramePvP = false; private bool lastFramePvP = false;
[ServiceManager.ServiceConstructor] [ServiceManager.ServiceConstructor]
private ClientState(SigScanner sigScanner, DalamudStartInfo startInfo) private ClientState(SigScanner sigScanner, DalamudStartInfo startInfo, GameLifecycle lifecycle)
{ {
this.lifecycle = lifecycle;
this.address = new ClientStateAddressResolver(); this.address = new ClientStateAddressResolver();
this.address.Setup(sigScanner); this.address.Setup(sigScanner);
@ -174,6 +176,8 @@ public sealed class ClientState : IDisposable, IServiceType
this.IsLoggedIn = true; this.IsLoggedIn = true;
this.Login?.InvokeSafely(this, null); this.Login?.InvokeSafely(this, null);
gameGui.ResetUiHideState(); gameGui.ResetUiHideState();
this.lifecycle.ResetLogout();
} }
if (!condition.Any() && this.lastConditionNone == false) if (!condition.Any() && this.lastConditionNone == false)
@ -183,6 +187,8 @@ public sealed class ClientState : IDisposable, IServiceType
this.IsLoggedIn = false; this.IsLoggedIn = false;
this.Logout?.InvokeSafely(this, null); this.Logout?.InvokeSafely(this, null);
gameGui.ResetUiHideState(); gameGui.ResetUiHideState();
this.lifecycle.SetLogout();
} }
this.IsPvP = GameMain.IsInPvPArea(); this.IsPvP = GameMain.IsInPvPArea();

View file

@ -25,6 +25,8 @@ namespace Dalamud.Game;
[ServiceManager.BlockingEarlyLoadedService] [ServiceManager.BlockingEarlyLoadedService]
public sealed class Framework : IDisposable, IServiceType public sealed class Framework : IDisposable, IServiceType
{ {
private readonly GameLifecycle lifecycle;
private static Stopwatch statsStopwatch = new(); private static Stopwatch statsStopwatch = new();
private readonly Stopwatch updateStopwatch = new(); private readonly Stopwatch updateStopwatch = new();
@ -41,10 +43,11 @@ public sealed class Framework : IDisposable, IServiceType
[ServiceManager.ServiceDependency] [ServiceManager.ServiceDependency]
private readonly DalamudConfiguration configuration = Service<DalamudConfiguration>.Get(); private readonly DalamudConfiguration configuration = Service<DalamudConfiguration>.Get();
[ServiceManager.ServiceConstructor] [ServiceManager.ServiceConstructor]
private Framework(SigScanner sigScanner) private Framework(SigScanner sigScanner, GameLifecycle lifecycle)
{ {
this.lifecycle = lifecycle;
this.hitchDetector = new HitchDetector("FrameworkUpdate", this.configuration.FrameworkUpdateHitch); this.hitchDetector = new HitchDetector("FrameworkUpdate", this.configuration.FrameworkUpdateHitch);
this.Address = new FrameworkAddressResolver(); this.Address = new FrameworkAddressResolver();
@ -489,6 +492,10 @@ public sealed class Framework : IDisposable, IServiceType
this.IsFrameworkUnloading = true; this.IsFrameworkUnloading = true;
this.DispatchUpdateEvents = false; this.DispatchUpdateEvents = false;
// All the same, for now...
this.lifecycle.SetShuttingDown();
this.lifecycle.SetUnloading();
Log.Information("Framework::Destroy!"); Log.Information("Framework::Destroy!");
Service<Dalamud>.Get().Unload(); Service<Dalamud>.Get().Unload();
this.RunPendingTickTasks(); this.RunPendingTickTasks();

View file

@ -0,0 +1,63 @@
using System.Threading;
using Dalamud.IoC;
using Dalamud.IoC.Internal;
namespace Dalamud.Game;
/// <summary>
/// Class offering cancellation tokens for common gameplay events.
/// </summary>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
public class GameLifecycle : IServiceType
{
private readonly CancellationTokenSource dalamudUnloadCts = new();
private readonly CancellationTokenSource gameShutdownCts = new();
private CancellationTokenSource logoutCts = new();
/// <summary>
/// Initializes a new instance of the <see cref="GameLifecycle"/> class.
/// </summary>
[ServiceManager.ServiceConstructor]
internal GameLifecycle()
{
}
/// <summary>
/// Gets a token that is cancelled when Dalamud is unloading.
/// </summary>
public CancellationToken DalamudUnloadingToken => this.dalamudUnloadCts.Token;
/// <summary>
/// Gets a token that is cancelled when the game is shutting down.
/// </summary>
public CancellationToken GameShuttingDownToken => this.gameShutdownCts.Token;
/// <summary>
/// Gets a token that is cancelled when a character is logging out.
/// </summary>
public CancellationToken LogoutToken => this.logoutCts.Token;
/// <summary>
/// Mark an unload.
/// </summary>
internal void SetUnloading() => this.dalamudUnloadCts.Cancel();
/// <summary>
/// Mark a shutdown.
/// </summary>
internal void SetShuttingDown() => this.gameShutdownCts.Cancel();
/// <summary>
/// Mark a logout.
/// </summary>
internal void SetLogout() => this.logoutCts.Cancel();
/// <summary>
/// Unmark a logout.
/// </summary>
internal void ResetLogout() => this.logoutCts = new();
}

View file

@ -61,6 +61,14 @@ public class SwapChainVtableResolver : BaseAddressResolver, ISwapChainAddressRes
{ {
if (processModule.FileName != null && processModule.FileName.EndsWith("game\\dxgi.dll")) if (processModule.FileName != null && processModule.FileName.EndsWith("game\\dxgi.dll"))
{ {
var fileInfo = FileVersionInfo.GetVersionInfo(processModule.FileName);
if (fileInfo.FileDescription == null)
break;
if (!fileInfo.FileDescription.Contains("GShade") && !fileInfo.FileDescription.Contains("ReShade"))
break;
// reshade master@4232872 RVA // reshade master@4232872 RVA
// var p = processModule.BaseAddress + 0x82C7E0; // DXGISwapChain::Present // var p = processModule.BaseAddress + 0x82C7E0; // DXGISwapChain::Present
// var p = processModule.BaseAddress + 0x82FAC0; // DXGISwapChain::runtime_present // var p = processModule.BaseAddress + 0x82FAC0; // DXGISwapChain::runtime_present
@ -72,8 +80,6 @@ public class SwapChainVtableResolver : BaseAddressResolver, ISwapChainAddressRes
try try
{ {
var fileInfo = FileVersionInfo.GetVersionInfo(processModule.FileName);
// Looks like this sig only works for GShade 4 // Looks like this sig only works for GShade 4
if (fileInfo.FileDescription?.Contains("GShade 4.") == true) if (fileInfo.FileDescription?.Contains("GShade 4.") == true)
{ {

View file

@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Numerics; using System.Numerics;
using Dalamud.Game.ClientState.Keys; using Dalamud.Game.ClientState.Keys;
using Dalamud.Interface.Raii;
using ImGuiNET; using ImGuiNET;
using ImGuiScene; using ImGuiScene;
@ -161,9 +162,10 @@ public static class ImGuiHelpers
/// <param name="text">The text to write.</param> /// <param name="text">The text to write.</param>
public static void SafeTextColoredWrapped(Vector4 color, string text) public static void SafeTextColoredWrapped(Vector4 color, string text)
{ {
ImGui.PushStyleColor(ImGuiCol.Text, color); using (ImRaii.PushColor(ImGuiCol.Text, color))
ImGui.TextWrapped(text.Replace("%", "%%")); {
ImGui.PopStyleColor(); ImGui.TextWrapped(text.Replace("%", "%%"));
}
} }
/// <summary> /// <summary>

View file

@ -21,6 +21,7 @@ using Dalamud.Interface.Internal.Windows.PluginInstaller;
using Dalamud.Interface.Internal.Windows.SelfTest; using Dalamud.Interface.Internal.Windows.SelfTest;
using Dalamud.Interface.Internal.Windows.Settings; using Dalamud.Interface.Internal.Windows.Settings;
using Dalamud.Interface.Internal.Windows.StyleEditor; using Dalamud.Interface.Internal.Windows.StyleEditor;
using Dalamud.Interface.Raii;
using Dalamud.Interface.Style; using Dalamud.Interface.Style;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using Dalamud.Logging; using Dalamud.Logging;
@ -538,7 +539,8 @@ internal class DalamudInterface : IDisposable, IServiceType
private void DrawCreditsDarkeningAnimation() private void DrawCreditsDarkeningAnimation()
{ {
ImGui.PushStyleVar(ImGuiStyleVar.WindowRounding, 0f); using var style = ImRaii.PushStyle(ImGuiStyleVar.WindowRounding, 0f);
ImGui.SetNextWindowPos(new Vector2(0, 0)); ImGui.SetNextWindowPos(new Vector2(0, 0));
ImGui.SetNextWindowSize(ImGuiHelpers.MainViewport.Size); ImGui.SetNextWindowSize(ImGuiHelpers.MainViewport.Size);
ImGuiHelpers.ForceNextWindowMainViewport(); ImGuiHelpers.ForceNextWindowMainViewport();
@ -552,8 +554,6 @@ internal class DalamudInterface : IDisposable, IServiceType
ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.NoBringToFrontOnFocus | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.NoBringToFrontOnFocus |
ImGuiWindowFlags.NoNav); ImGuiWindowFlags.NoNav);
ImGui.End(); ImGui.End();
ImGui.PopStyleVar();
} }
private void DrawHiddenDevMenuOpener() private void DrawHiddenDevMenuOpener()
@ -562,18 +562,17 @@ internal class DalamudInterface : IDisposable, IServiceType
if (!this.isImGuiDrawDevMenu && !condition.Any()) if (!this.isImGuiDrawDevMenu && !condition.Any())
{ {
ImGui.PushStyleColor(ImGuiCol.Button, Vector4.Zero); using var color = ImRaii.PushColor(ImGuiCol.Button, Vector4.Zero);
ImGui.PushStyleColor(ImGuiCol.ButtonActive, Vector4.Zero); color.Push(ImGuiCol.ButtonActive, Vector4.Zero);
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, Vector4.Zero); color.Push(ImGuiCol.ButtonHovered, Vector4.Zero);
ImGui.PushStyleColor(ImGuiCol.TextSelectedBg, new Vector4(0, 0, 0, 1)); color.Push(ImGuiCol.TextSelectedBg, new Vector4(0, 0, 0, 1));
ImGui.PushStyleColor(ImGuiCol.Border, new Vector4(0, 0, 0, 1)); color.Push(ImGuiCol.Border, new Vector4(0, 0, 0, 1));
ImGui.PushStyleColor(ImGuiCol.BorderShadow, new Vector4(0, 0, 0, 1)); color.Push(ImGuiCol.BorderShadow, new Vector4(0, 0, 0, 1));
ImGui.PushStyleColor(ImGuiCol.WindowBg, new Vector4(0, 0, 0, 1)); color.Push(ImGuiCol.WindowBg, new Vector4(0, 0, 0, 1));
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero); using var style = ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, Vector2.Zero);
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, Vector2.Zero); style.Push(ImGuiStyleVar.WindowBorderSize, 0);
ImGui.PushStyleVar(ImGuiStyleVar.WindowBorderSize, 0); style.Push(ImGuiStyleVar.FrameBorderSize, 0);
ImGui.PushStyleVar(ImGuiStyleVar.FrameBorderSize, 0);
var windowPos = ImGui.GetMainViewport().Pos + new Vector2(20); var windowPos = ImGui.GetMainViewport().Pos + new Vector2(20);
ImGui.SetNextWindowPos(windowPos, ImGuiCond.Always); ImGui.SetNextWindowPos(windowPos, ImGuiCond.Always);
@ -605,9 +604,6 @@ internal class DalamudInterface : IDisposable, IServiceType
ImGui.End(); ImGui.End();
} }
ImGui.PopStyleVar(4);
ImGui.PopStyleColor(7);
} }
} }
@ -775,6 +771,12 @@ internal class DalamudInterface : IDisposable, IServiceType
} }
} }
if (ImGui.MenuItem("Report crashes at shutdown", null, configuration.ReportShutdownCrashes))
{
configuration.ReportShutdownCrashes = !configuration.ReportShutdownCrashes;
configuration.QueueSave();
}
ImGui.Separator(); ImGui.Separator();
if (ImGui.MenuItem("Open Dalamud branch switcher")) if (ImGui.MenuItem("Open Dalamud branch switcher"))

View file

@ -21,6 +21,14 @@ public class DalamudTextureWrap : TextureWrap
this.wrappedWrap = wrappingWrap; this.wrappedWrap = wrappingWrap;
} }
/// <summary>
/// Finalizes an instance of the <see cref="DalamudTextureWrap"/> class.
/// </summary>
~DalamudTextureWrap()
{
this.Dispose(false);
}
/// <summary> /// <summary>
/// Gets the ImGui handle of the texture. /// Gets the ImGui handle of the texture.
/// </summary> /// </summary>
@ -41,7 +49,8 @@ public class DalamudTextureWrap : TextureWrap
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
Service<InterfaceManager>.Get().EnqueueDeferredDispose(this); this.Dispose(true);
GC.SuppressFinalize(this);
} }
/// <summary> /// <summary>
@ -51,4 +60,12 @@ public class DalamudTextureWrap : TextureWrap
{ {
this.wrappedWrap.Dispose(); this.wrappedWrap.Dispose();
} }
private void Dispose(bool disposing)
{
if (disposing)
{
Service<InterfaceManager>.GetNullable()?.EnqueueDeferredDispose(this);
}
}
} }

View file

@ -606,12 +606,16 @@ internal class InterfaceManager : IDisposable, IServiceType
this.RenderImGui(); this.RenderImGui();
foreach (var texture in this.deferredDisposeTextures) if (this.deferredDisposeTextures.Count > 0)
{ {
texture.RealDispose(); Log.Verbose("[IM] Disposing {Count} textures", this.deferredDisposeTextures.Count);
} foreach (var texture in this.deferredDisposeTextures)
{
texture.RealDispose();
}
this.deferredDisposeTextures.Clear(); this.deferredDisposeTextures.Clear();
}
return this.presentHook.Original(swapChain, syncInterval, presentFlags); return this.presentHook.Original(swapChain, syncInterval, presentFlags);
} }

View file

@ -348,46 +348,46 @@ internal class PluginInstallerWindow : Window, IDisposable
ImGuiHelpers.CenteredText("Installing plugin..."); ImGuiHelpers.CenteredText("Installing plugin...");
break; break;
case LoadingIndicatorKind.Manager: case LoadingIndicatorKind.Manager:
{
if (pluginManager.PluginsReady && !pluginManager.ReposReady)
{ {
ImGuiHelpers.CenteredText("Loading repositories..."); if (pluginManager.PluginsReady && !pluginManager.ReposReady)
} {
else if (!pluginManager.PluginsReady && pluginManager.ReposReady) ImGuiHelpers.CenteredText("Loading repositories...");
{ }
ImGuiHelpers.CenteredText("Loading installed plugins..."); else if (!pluginManager.PluginsReady && pluginManager.ReposReady)
} {
else ImGuiHelpers.CenteredText("Loading installed plugins...");
{ }
ImGuiHelpers.CenteredText("Loading repositories and plugins..."); else
} {
ImGuiHelpers.CenteredText("Loading repositories and plugins...");
}
var currentProgress = 0; var currentProgress = 0;
var total = 0; var total = 0;
var pendingRepos = pluginManager.Repos.ToArray() var pendingRepos = pluginManager.Repos.ToArray()
.Where(x => (x.State != PluginRepositoryState.Success && .Where(x => (x.State != PluginRepositoryState.Success &&
x.State != PluginRepositoryState.Fail) && x.State != PluginRepositoryState.Fail) &&
x.IsEnabled) x.IsEnabled)
.ToArray(); .ToArray();
var allRepoCount = var allRepoCount =
pluginManager.Repos.Count(x => x.State != PluginRepositoryState.Fail && x.IsEnabled); pluginManager.Repos.Count(x => x.State != PluginRepositoryState.Fail && x.IsEnabled);
foreach (var repo in pendingRepos) foreach (var repo in pendingRepos)
{ {
ImGuiHelpers.CenteredText($"{repo.PluginMasterUrl}: {repo.State}"); ImGuiHelpers.CenteredText($"{repo.PluginMasterUrl}: {repo.State}");
}
currentProgress += allRepoCount - pendingRepos.Length;
total += allRepoCount;
if (currentProgress != total)
{
ImGui.SetCursorPosX(windowSize.X / 3);
ImGui.ProgressBar(currentProgress / (float)total, new Vector2(windowSize.X / 3, 50));
}
} }
currentProgress += allRepoCount - pendingRepos.Length;
total += allRepoCount;
if (currentProgress != total)
{
ImGui.SetCursorPosX(windowSize.X / 3);
ImGui.ProgressBar(currentProgress / (float)total, new Vector2(windowSize.X / 3, 50));
}
}
break; break;
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
@ -2199,9 +2199,12 @@ internal class PluginInstallerWindow : Window, IDisposable
ImGui.TextColored(ImGuiColors.DalamudGrey3, downloadText); ImGui.TextColored(ImGuiColors.DalamudGrey3, downloadText);
var isThirdParty = manifest.IsThirdParty; var isThirdParty = manifest.IsThirdParty;
var canFeedback = !isThirdParty && !plugin.IsDev && var canFeedback = !isThirdParty &&
!plugin.IsDev &&
!plugin.IsOrphaned &&
plugin.Manifest.DalamudApiLevel == PluginManager.DalamudApiLevel && plugin.Manifest.DalamudApiLevel == PluginManager.DalamudApiLevel &&
plugin.Manifest.AcceptsFeedback && availablePluginUpdate == default; plugin.Manifest.AcceptsFeedback &&
availablePluginUpdate == default;
// Installed from // Installed from
if (plugin.IsDev) if (plugin.IsDev)

View file

@ -5,6 +5,7 @@ using CheapLoc;
using Dalamud.Configuration.Internal; using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors; using Dalamud.Interface.Colors;
using Dalamud.Interface.Internal.Windows.Settings.Tabs; using Dalamud.Interface.Internal.Windows.Settings.Tabs;
using Dalamud.Interface.Raii;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using Dalamud.Plugin.Internal; using Dalamud.Plugin.Internal;
using Dalamud.Utility; using Dalamud.Utility;
@ -159,33 +160,27 @@ internal class SettingsWindow : Window
if (ImGui.BeginChild("###settingsFinishButton")) if (ImGui.BeginChild("###settingsFinishButton"))
{ {
ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 100f); using var disabled = ImRaii.Disabled(this.tabs.Any(x => x.Entries.Any(y => !y.IsValid)));
ImGui.PushFont(InterfaceManager.IconFont);
var invalid = this.tabs.Any(x => x.Entries.Any(y => !y.IsValid)); using (ImRaii.PushStyle(ImGuiStyleVar.FrameRounding, 100f))
if (invalid)
ImGui.BeginDisabled();
if (ImGui.Button(FontAwesomeIcon.Save.ToIconString(), new Vector2(40)))
{ {
this.Save(); using var font = ImRaii.PushFont(InterfaceManager.IconFont);
if (!ImGui.IsKeyDown(ImGuiKey.ModShift)) if (ImGui.Button(FontAwesomeIcon.Save.ToIconString(), new Vector2(40)))
this.IsOpen = false; {
this.Save();
if (!ImGui.IsKeyDown(ImGuiKey.ModShift))
this.IsOpen = false;
}
} }
ImGui.PopStyleVar();
ImGui.PopFont();
if (ImGui.IsItemHovered()) if (ImGui.IsItemHovered())
{ {
ImGui.SetTooltip(!ImGui.IsKeyDown(ImGuiKey.ModShift) ImGui.SetTooltip(!ImGui.IsKeyDown(ImGuiKey.ModShift)
? Loc.Localize("DalamudSettingsSaveAndExit", "Save changes and close") ? Loc.Localize("DalamudSettingsSaveAndExit", "Save changes and close")
: Loc.Localize("DalamudSettingsSaveAndExit", "Save changes")); : Loc.Localize("DalamudSettingsSaveAndExit", "Save changes"));
} }
if (invalid)
ImGui.EndDisabled();
} }
ImGui.EndChild(); ImGui.EndChild();

View file

@ -8,6 +8,7 @@ using System.Numerics;
using CheapLoc; using CheapLoc;
using Dalamud.Game.Gui; using Dalamud.Game.Gui;
using Dalamud.Interface.GameFonts; using Dalamud.Interface.GameFonts;
using Dalamud.Interface.Raii;
using Dalamud.Plugin.Internal; using Dalamud.Plugin.Internal;
using Dalamud.Utility; using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Client.Game.UI; using FFXIVClientStructs.FFXIV.Client.Game.UI;
@ -243,46 +244,45 @@ Contribute at: https://github.com/goatcorp/Dalamud
this.resetNow = false; this.resetNow = false;
} }
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero); using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero))
ImGuiHelpers.ScaledDummy(0, windowSize.Y + 20f);
ImGui.Text(string.Empty);
const float imageSize = 190f;
ImGui.SameLine((ImGui.GetWindowWidth() / 2) - (imageSize / 2));
ImGui.Image(this.logoTexture.ImGuiHandle, ImGuiHelpers.ScaledVector2(imageSize));
ImGuiHelpers.ScaledDummy(0, 20f);
var windowX = ImGui.GetWindowSize().X;
foreach (var creditsLine in this.creditsText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None))
{ {
var lineLenX = ImGui.CalcTextSize(creditsLine).X; ImGuiHelpers.ScaledDummy(0, windowSize.Y + 20f);
ImGui.Text(string.Empty);
ImGui.Dummy(new Vector2((windowX / 2) - (lineLenX / 2), 0f)); const float imageSize = 190f;
ImGui.SameLine(); ImGui.SameLine((ImGui.GetWindowWidth() / 2) - (imageSize / 2));
ImGui.TextUnformatted(creditsLine); ImGui.Image(this.logoTexture.ImGuiHandle, ImGuiHelpers.ScaledVector2(imageSize));
ImGuiHelpers.ScaledDummy(0, 20f);
var windowX = ImGui.GetWindowSize().X;
foreach (var creditsLine in this.creditsText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None))
{
var lineLenX = ImGui.CalcTextSize(creditsLine).X;
ImGui.Dummy(new Vector2((windowX / 2) - (lineLenX / 2), 0f));
ImGui.SameLine();
ImGui.TextUnformatted(creditsLine);
}
ImGuiHelpers.ScaledDummy(0, 40f);
if (this.thankYouFont != null)
{
ImGui.PushFont(this.thankYouFont.ImFont);
var thankYouLenX = ImGui.CalcTextSize(ThankYouText).X;
ImGui.Dummy(new Vector2((windowX / 2) - (thankYouLenX / 2), 0f));
ImGui.SameLine();
ImGui.TextUnformatted(ThankYouText);
ImGui.PopFont();
}
ImGuiHelpers.ScaledDummy(0, windowSize.Y + 50f);
} }
ImGuiHelpers.ScaledDummy(0, 40f);
if (this.thankYouFont != null)
{
ImGui.PushFont(this.thankYouFont.ImFont);
var thankYouLenX = ImGui.CalcTextSize(ThankYouText).X;
ImGui.Dummy(new Vector2((windowX / 2) - (thankYouLenX / 2), 0f));
ImGui.SameLine();
ImGui.TextUnformatted(ThankYouText);
ImGui.PopFont();
}
ImGuiHelpers.ScaledDummy(0, windowSize.Y + 50f);
ImGui.PopStyleVar();
if (this.creditsThrottler.Elapsed.TotalMilliseconds > (1000.0f / CreditFps)) if (this.creditsThrottler.Elapsed.TotalMilliseconds > (1000.0f / CreditFps))
{ {
var curY = ImGui.GetScrollY(); var curY = ImGui.GetScrollY();

View file

@ -27,7 +27,8 @@ public class SettingsTabGeneral : SettingsTab
return Loc.Localize("DalamudSettingsChannelNone", "Do not pick \"None\"."); return Loc.Localize("DalamudSettingsChannelNone", "Do not pick \"None\".");
return null; return null;
}), },
fallbackValue: XivChatType.Debug),
new GapSettingsEntry(5), new GapSettingsEntry(5),

View file

@ -10,6 +10,7 @@ using Dalamud.Configuration;
using Dalamud.Configuration.Internal; using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors; using Dalamud.Interface.Colors;
using Dalamud.Interface.Components; using Dalamud.Interface.Components;
using Dalamud.Interface.Raii;
using Dalamud.Plugin.Internal; using Dalamud.Plugin.Internal;
using ImGuiNET; using ImGuiNET;
@ -57,10 +58,11 @@ public class DevPluginsSettingsEntry : SettingsEntry
ImGui.Text(this.Name); ImGui.Text(this.Name);
if (this.devPluginLocationsChanged) if (this.devPluginLocationsChanged)
{ {
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen); using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.HealerGreen))
ImGui.SameLine(); {
ImGui.Text(Loc.Localize("DalamudSettingsChanged", "(Changed)")); ImGui.SameLine();
ImGui.PopStyleColor(); ImGui.Text(Loc.Localize("DalamudSettingsChanged", "(Changed)"));
}
} }
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsDevPluginLocationsHint", "Add additional dev plugin load locations.\nThese can be either the directory or DLL path.")); ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsDevPluginLocationsHint", "Add additional dev plugin load locations.\nThese can be either the directory or DLL path."));

View file

@ -7,6 +7,7 @@ using System.Linq;
using Dalamud.Configuration.Internal; using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors; using Dalamud.Interface.Colors;
using Dalamud.Interface.Raii;
using Dalamud.Utility; using Dalamud.Utility;
using ImGuiNET; using ImGuiNET;
@ -20,8 +21,10 @@ internal sealed class SettingsEntry<T> : SettingsEntry
private readonly Action<T?>? change; private readonly Action<T?>? change;
private object? valueBacking; private object? valueBacking;
private object? fallbackValue;
public SettingsEntry(string name, string description, LoadSettingDelegate load, SaveSettingDelegate save, Action<T?>? change = null, Func<T?, string?>? warning = null, Func<T?, string?>? validity = null, Func<bool>? visibility = null) public SettingsEntry(string name, string description, LoadSettingDelegate load, SaveSettingDelegate save, Action<T?>? change = null, Func<T?, string?>? warning = null, Func<T?, string?>? validity = null, Func<bool>? visibility = null,
object? fallbackValue = null)
{ {
this.load = load; this.load = load;
this.save = save; this.save = save;
@ -31,6 +34,8 @@ internal sealed class SettingsEntry<T> : SettingsEntry
this.CheckWarning = warning; this.CheckWarning = warning;
this.CheckValidity = validity; this.CheckValidity = validity;
this.CheckVisibility = visibility; this.CheckVisibility = visibility;
this.fallbackValue = fallbackValue;
} }
public delegate T? LoadSettingDelegate(DalamudConfiguration config); public delegate T? LoadSettingDelegate(DalamudConfiguration config);
@ -97,6 +102,12 @@ internal sealed class SettingsEntry<T> : SettingsEntry
var descriptions = var descriptions =
values.Cast<Enum>().ToDictionary(x => x, x => x.GetAttribute<SettingsAnnotationAttribute>() ?? new SettingsAnnotationAttribute(x.ToString(), string.Empty)); values.Cast<Enum>().ToDictionary(x => x, x => x.GetAttribute<SettingsAnnotationAttribute>() ?? new SettingsAnnotationAttribute(x.ToString(), string.Empty));
if (!descriptions.ContainsKey(idx))
{
idx = (Enum)this.fallbackValue ?? throw new Exception("No fallback value for enum");
this.valueBacking = idx;
}
if (ImGui.BeginCombo($"###{this.Id.ToString()}", descriptions[idx].FriendlyName)) if (ImGui.BeginCombo($"###{this.Id.ToString()}", descriptions[idx].FriendlyName))
{ {
foreach (Enum value in values) foreach (Enum value in values)
@ -111,9 +122,10 @@ internal sealed class SettingsEntry<T> : SettingsEntry
} }
} }
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey); using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudGrey))
ImGuiHelpers.SafeTextWrapped(this.Description); {
ImGui.PopStyleColor(); ImGuiHelpers.SafeTextWrapped(this.Description);
}
if (this.CheckValidity != null) if (this.CheckValidity != null)
{ {
@ -122,9 +134,10 @@ internal sealed class SettingsEntry<T> : SettingsEntry
if (!this.IsValid) if (!this.IsValid)
{ {
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed); using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed))
ImGui.Text(validityMsg); {
ImGui.PopStyleColor(); ImGui.Text(validityMsg);
}
} }
} }
else else
@ -136,9 +149,10 @@ internal sealed class SettingsEntry<T> : SettingsEntry
if (warningMessage != null) if (warningMessage != null)
{ {
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed); using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed))
ImGui.Text(warningMessage); {
ImGui.PopStyleColor(); ImGui.Text(warningMessage);
}
} }
} }

View file

@ -10,6 +10,7 @@ using Dalamud.Configuration;
using Dalamud.Configuration.Internal; using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors; using Dalamud.Interface.Colors;
using Dalamud.Interface.Components; using Dalamud.Interface.Components;
using Dalamud.Interface.Raii;
using Dalamud.Plugin.Internal; using Dalamud.Plugin.Internal;
using ImGuiNET; using ImGuiNET;
@ -53,10 +54,11 @@ public class ThirdRepoSettingsEntry : SettingsEntry
ImGui.Text(Loc.Localize("DalamudSettingsCustomRepo", "Custom Plugin Repositories")); ImGui.Text(Loc.Localize("DalamudSettingsCustomRepo", "Custom Plugin Repositories"));
if (this.thirdRepoListChanged) if (this.thirdRepoListChanged)
{ {
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen); using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.HealerGreen))
ImGui.SameLine(); {
ImGui.Text(Loc.Localize("DalamudSettingsChanged", "(Changed)")); ImGui.SameLine();
ImGui.PopStyleColor(); ImGui.Text(Loc.Localize("DalamudSettingsChanged", "(Changed)"));
}
} }
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingCustomRepoHint", "Add custom plugin repositories.")); ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingCustomRepoHint", "Add custom plugin repositories."));

View file

@ -9,6 +9,7 @@ using Dalamud.Game;
using Dalamud.Game.ClientState; using Dalamud.Game.ClientState;
using Dalamud.Game.Gui; using Dalamud.Game.Gui;
using Dalamud.Interface.Animation.EasingFunctions; using Dalamud.Interface.Animation.EasingFunctions;
using Dalamud.Interface.Raii;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using ImGuiNET; using ImGuiNET;
using ImGuiScene; using ImGuiScene;
@ -169,23 +170,22 @@ internal class TitleScreenMenuWindow : Window, IDisposable
this.fadeOutEasing.Update(); this.fadeOutEasing.Update();
ImGui.PushStyleVar(ImGuiStyleVar.Alpha, (float)this.fadeOutEasing.Value); using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)this.fadeOutEasing.Value))
for (var i = 0; i < tsm.Entries.Count; i++)
{ {
var entry = tsm.Entries[i]; for (var i = 0; i < tsm.Entries.Count; i++)
{
var entry = tsm.Entries[i];
var finalPos = (i + 1) * this.shadeTexture.Height * scale; var finalPos = (i + 1) * this.shadeTexture.Height * scale;
this.DrawEntry(entry, i != 0, true, i == 0, false, false); this.DrawEntry(entry, i != 0, true, i == 0, false, false);
var cursor = ImGui.GetCursorPos(); var cursor = ImGui.GetCursorPos();
cursor.Y = finalPos; cursor.Y = finalPos;
ImGui.SetCursorPos(cursor); ImGui.SetCursorPos(cursor);
}
} }
ImGui.PopStyleVar();
var isHover = ImGui.IsWindowHovered(ImGuiHoveredFlags.RootAndChildWindows | var isHover = ImGui.IsWindowHovered(ImGuiHoveredFlags.RootAndChildWindows |
ImGuiHoveredFlags.AllowWhenBlockedByActiveItem); ImGuiHoveredFlags.AllowWhenBlockedByActiveItem);
@ -254,9 +254,11 @@ internal class TitleScreenMenuWindow : Window, IDisposable
var initialCursor = ImGui.GetCursorPos(); var initialCursor = ImGui.GetCursorPos();
ImGui.PushStyleVar(ImGuiStyleVar.Alpha, (float)shadeEasing.Value);
ImGui.Image(this.shadeTexture.ImGuiHandle, new Vector2(this.shadeTexture.Width * scale, this.shadeTexture.Height * scale)); using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)shadeEasing.Value))
ImGui.PopStyleVar(); {
ImGui.Image(this.shadeTexture.ImGuiHandle, new Vector2(this.shadeTexture.Width * scale, this.shadeTexture.Height * scale));
}
var isHover = ImGui.IsItemHovered(); var isHover = ImGui.IsItemHovered();
if (isHover && (!shadeEasing.IsRunning || (shadeEasing.IsDone && shadeEasing.IsInverse)) && !inhibitFadeout) if (isHover && (!shadeEasing.IsRunning || (shadeEasing.IsDone && shadeEasing.IsInverse)) && !inhibitFadeout)
@ -331,15 +333,15 @@ internal class TitleScreenMenuWindow : Window, IDisposable
} }
// Drop shadow // Drop shadow
ImGui.PushStyleColor(ImGuiCol.Text, 0xFF000000); using (ImRaii.PushColor(ImGuiCol.Text, 0xFF000000))
for (int i = 0, i_ = (int)Math.Ceiling(1 * scale); i < i_; i++)
{ {
ImGui.SetCursorPos(new Vector2(cursor.X, cursor.Y + i)); for (int i = 0, i_ = (int)Math.Ceiling(1 * scale); i < i_; i++)
ImGui.Text(entry.Name); {
ImGui.SetCursorPos(new Vector2(cursor.X, cursor.Y + i));
ImGui.Text(entry.Name);
}
} }
ImGui.PopStyleColor();
ImGui.SetCursorPos(cursor); ImGui.SetCursorPos(cursor);
ImGui.Text(entry.Name); ImGui.Text(entry.Name);

View file

@ -251,7 +251,7 @@ Thanks and have fun!";
new TextPayload(" ["), new TextPayload(" ["),
new UIForegroundPayload(500), new UIForegroundPayload(500),
this.openInstallerWindowPluginChangelogsLink, this.openInstallerWindowPluginChangelogsLink,
new TextPayload(Loc.Localize("DalamudInstallerPluginChangelogHelp", "Open plugin changelogs") + " "), new TextPayload(Loc.Localize("DalamudInstallerPluginChangelogHelp", "Open plugin changelogs")),
RawPayload.LinkTerminator, RawPayload.LinkTerminator,
new UIForegroundPayload(0), new UIForegroundPayload(0),
new TextPayload("]"), new TextPayload("]"),
@ -262,13 +262,13 @@ Thanks and have fun!";
{ {
if (metadata.WasUpdated) if (metadata.WasUpdated)
{ {
chatGui.Print(Locs.DalamudPluginUpdateSuccessful(metadata.Name, metadata.Version) + (metadata.HasChangelog ? " " : string.Empty)); chatGui.Print(Locs.DalamudPluginUpdateSuccessful(metadata.Name, metadata.Version));
} }
else else
{ {
chatGui.PrintChat(new XivChatEntry chatGui.PrintChat(new XivChatEntry
{ {
Message = Locs.DalamudPluginUpdateFailed(metadata.Name, metadata.Version) + (metadata.HasChangelog ? " " : string.Empty), Message = Locs.DalamudPluginUpdateFailed(metadata.Name, metadata.Version),
Type = XivChatType.Urgent, Type = XivChatType.Urgent,
}); });
} }

View file

@ -739,6 +739,11 @@ int main() {
std::cout << "Crash triggered" << std::endl; std::cout << "Crash triggered" << std::endl;
auto shutup_mutex = CreateMutex(NULL, false, L"DALAMUD_CRASHES_NO_MORE");
bool shutup = false;
if (shutup_mutex == NULL && GetLastError() == ERROR_ALREADY_EXISTS)
shutup = true;
/* /*
Hard won wisdom: changing symbol path with SymSetSearchPath() after modules Hard won wisdom: changing symbol path with SymSetSearchPath() after modules
have been loaded (invadeProcess=TRUE in SymInitialize() or SymRefreshModuleList()) have been loaded (invadeProcess=TRUE in SymInitialize() or SymRefreshModuleList())
@ -795,7 +800,11 @@ int main() {
std::wstring dumpError; std::wstring dumpError;
if (dumpPath.empty()) { if (dumpPath.empty()) {
std::cout << "Skipping dump path, as log directory has not been specified" << std::endl; std::cout << "Skipping dump path, as log directory has not been specified" << std::endl;
} else { } else if (shutup) {
std::cout << "Skipping dump, was shutdown" << std::endl;
}
else
{
MINIDUMP_EXCEPTION_INFORMATION mdmp_info{}; MINIDUMP_EXCEPTION_INFORMATION mdmp_info{};
mdmp_info.ThreadId = GetThreadId(exinfo.hThreadHandle); mdmp_info.ThreadId = GetThreadId(exinfo.hThreadHandle);
mdmp_info.ExceptionPointers = exinfo.pExceptionPointers; mdmp_info.ExceptionPointers = exinfo.pExceptionPointers;
@ -821,6 +830,10 @@ int main() {
std::wostringstream log; std::wostringstream log;
log << std::format(L"Unhandled native exception occurred at {}", to_address_string(exinfo.ContextRecord.Rip, false)) << std::endl; log << std::format(L"Unhandled native exception occurred at {}", to_address_string(exinfo.ContextRecord.Rip, false)) << std::endl;
log << std::format(L"Code: {:X}", exinfo.ExceptionRecord.ExceptionCode) << std::endl; log << std::format(L"Code: {:X}", exinfo.ExceptionRecord.ExceptionCode) << std::endl;
if (shutup)
log << L"======= Crash handler was globally muted(shutdown?) =======" << std::endl;
if (dumpPath.empty()) if (dumpPath.empty())
log << L"Dump skipped" << std::endl; log << L"Dump skipped" << std::endl;
else if (dumpError.empty()) else if (dumpError.empty())
@ -971,6 +984,11 @@ int main() {
submitThread = {}; submitThread = {};
} }
if (shutup) {
TerminateProcess(g_hProcess, exinfo.ExceptionRecord.ExceptionCode);
return 0;
}
int nButtonPressed = 0, nRadioButton = 0; int nButtonPressed = 0, nRadioButton = 0;
if (FAILED(TaskDialogIndirect(&config, &nButtonPressed, &nRadioButton, nullptr))) { if (FAILED(TaskDialogIndirect(&config, &nButtonPressed, &nRadioButton, nullptr))) {
ResumeThread(exinfo.hThreadHandle); ResumeThread(exinfo.hThreadHandle);