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")
$revision = [System.IO.File]::ReadAllText("$(Get-Location)\scratch\revision.txt")
Remove-Item -Force -Recurse .\scratch
if (Test-Path -Path $branchName) {
@ -82,6 +83,7 @@ jobs:
Move-Item -Force ".\canary.zip" ".\${branchName}\latest.zip"
$versionData.AssemblyVersion = $newVersion
$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"
}

View file

@ -6,6 +6,8 @@
#include "hooks.h"
#include "logging.h"
#include "utils.h"
#include <iphlpapi.h>
#include <icmpapi.h>
template<typename T>
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) {
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 },
{ "redirect_openprocess", &redirect_openprocess },
{ "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 {

View file

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

View file

@ -325,7 +325,7 @@ namespace Dalamud.Injector
startInfo.BootShowConsole = args.Contains("--console");
startInfo.BootEnableEtw = args.Contains("--etw");
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.BootWaitMessageBox |= args.Contains("--msgbox1") ? 1 : 0;
startInfo.BootWaitMessageBox |= args.Contains("--msgbox2") ? 2 : 0;

View file

@ -244,6 +244,11 @@ internal sealed class DalamudConfiguration : IServiceType
/// </summary>
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>
/// Gets or sets a list of saved styles.
/// </summary>

View file

@ -11,6 +11,7 @@ using Dalamud.Game.Gui.Internal;
using Dalamud.Interface.Internal;
using Dalamud.Plugin.Internal;
using Dalamud.Utility;
using PInvoke;
using Serilog;
#if DEBUG
@ -103,6 +104,16 @@ internal sealed class Dalamud : IServiceType
public void 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();
}

View file

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

View file

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

View file

@ -25,6 +25,8 @@ namespace Dalamud.Game;
[ServiceManager.BlockingEarlyLoadedService]
public sealed class Framework : IDisposable, IServiceType
{
private readonly GameLifecycle lifecycle;
private static Stopwatch statsStopwatch = new();
private readonly Stopwatch updateStopwatch = new();
@ -41,10 +43,11 @@ public sealed class Framework : IDisposable, IServiceType
[ServiceManager.ServiceDependency]
private readonly DalamudConfiguration configuration = Service<DalamudConfiguration>.Get();
[ServiceManager.ServiceConstructor]
private Framework(SigScanner sigScanner)
private Framework(SigScanner sigScanner, GameLifecycle lifecycle)
{
this.lifecycle = lifecycle;
this.hitchDetector = new HitchDetector("FrameworkUpdate", this.configuration.FrameworkUpdateHitch);
this.Address = new FrameworkAddressResolver();
@ -489,6 +492,10 @@ public sealed class Framework : IDisposable, IServiceType
this.IsFrameworkUnloading = true;
this.DispatchUpdateEvents = false;
// All the same, for now...
this.lifecycle.SetShuttingDown();
this.lifecycle.SetUnloading();
Log.Information("Framework::Destroy!");
Service<Dalamud>.Get().Unload();
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"))
{
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
// var p = processModule.BaseAddress + 0x82C7E0; // DXGISwapChain::Present
// var p = processModule.BaseAddress + 0x82FAC0; // DXGISwapChain::runtime_present
@ -72,8 +80,6 @@ public class SwapChainVtableResolver : BaseAddressResolver, ISwapChainAddressRes
try
{
var fileInfo = FileVersionInfo.GetVersionInfo(processModule.FileName);
// Looks like this sig only works for GShade 4
if (fileInfo.FileDescription?.Contains("GShade 4.") == true)
{

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -8,6 +8,7 @@ using System.Numerics;
using CheapLoc;
using Dalamud.Game.Gui;
using Dalamud.Interface.GameFonts;
using Dalamud.Interface.Raii;
using Dalamud.Plugin.Internal;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Client.Game.UI;
@ -243,46 +244,45 @@ Contribute at: https://github.com/goatcorp/Dalamud
this.resetNow = false;
}
ImGui.PushStyleVar(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))
using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero))
{
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));
ImGui.SameLine();
ImGui.TextUnformatted(creditsLine);
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;
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))
{
var curY = ImGui.GetScrollY();

View file

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

View file

@ -10,6 +10,7 @@ using Dalamud.Configuration;
using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Interface.Raii;
using Dalamud.Plugin.Internal;
using ImGuiNET;
@ -57,10 +58,11 @@ public class DevPluginsSettingsEntry : SettingsEntry
ImGui.Text(this.Name);
if (this.devPluginLocationsChanged)
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen);
ImGui.SameLine();
ImGui.Text(Loc.Localize("DalamudSettingsChanged", "(Changed)"));
ImGui.PopStyleColor();
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.HealerGreen))
{
ImGui.SameLine();
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."));

View file

@ -7,6 +7,7 @@ using System.Linq;
using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Raii;
using Dalamud.Utility;
using ImGuiNET;
@ -20,8 +21,10 @@ internal sealed class SettingsEntry<T> : SettingsEntry
private readonly Action<T?>? change;
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.save = save;
@ -31,6 +34,8 @@ internal sealed class SettingsEntry<T> : SettingsEntry
this.CheckWarning = warning;
this.CheckValidity = validity;
this.CheckVisibility = visibility;
this.fallbackValue = fallbackValue;
}
public delegate T? LoadSettingDelegate(DalamudConfiguration config);
@ -97,6 +102,12 @@ internal sealed class SettingsEntry<T> : SettingsEntry
var descriptions =
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))
{
foreach (Enum value in values)
@ -111,9 +122,10 @@ internal sealed class SettingsEntry<T> : SettingsEntry
}
}
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey);
ImGuiHelpers.SafeTextWrapped(this.Description);
ImGui.PopStyleColor();
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudGrey))
{
ImGuiHelpers.SafeTextWrapped(this.Description);
}
if (this.CheckValidity != null)
{
@ -122,9 +134,10 @@ internal sealed class SettingsEntry<T> : SettingsEntry
if (!this.IsValid)
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
ImGui.Text(validityMsg);
ImGui.PopStyleColor();
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed))
{
ImGui.Text(validityMsg);
}
}
}
else
@ -136,9 +149,10 @@ internal sealed class SettingsEntry<T> : SettingsEntry
if (warningMessage != null)
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
ImGui.Text(warningMessage);
ImGui.PopStyleColor();
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed))
{
ImGui.Text(warningMessage);
}
}
}

View file

@ -10,6 +10,7 @@ using Dalamud.Configuration;
using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Interface.Raii;
using Dalamud.Plugin.Internal;
using ImGuiNET;
@ -53,10 +54,11 @@ public class ThirdRepoSettingsEntry : SettingsEntry
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();
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.HealerGreen))
{
ImGui.SameLine();
ImGui.Text(Loc.Localize("DalamudSettingsChanged", "(Changed)"));
}
}
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.Gui;
using Dalamud.Interface.Animation.EasingFunctions;
using Dalamud.Interface.Raii;
using Dalamud.Interface.Windowing;
using ImGuiNET;
using ImGuiScene;
@ -169,23 +170,22 @@ internal class TitleScreenMenuWindow : Window, IDisposable
this.fadeOutEasing.Update();
ImGui.PushStyleVar(ImGuiStyleVar.Alpha, (float)this.fadeOutEasing.Value);
for (var i = 0; i < tsm.Entries.Count; i++)
using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)this.fadeOutEasing.Value))
{
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();
cursor.Y = finalPos;
ImGui.SetCursorPos(cursor);
var cursor = ImGui.GetCursorPos();
cursor.Y = finalPos;
ImGui.SetCursorPos(cursor);
}
}
ImGui.PopStyleVar();
var isHover = ImGui.IsWindowHovered(ImGuiHoveredFlags.RootAndChildWindows |
ImGuiHoveredFlags.AllowWhenBlockedByActiveItem);
@ -254,9 +254,11 @@ internal class TitleScreenMenuWindow : Window, IDisposable
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));
ImGui.PopStyleVar();
using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)shadeEasing.Value))
{
ImGui.Image(this.shadeTexture.ImGuiHandle, new Vector2(this.shadeTexture.Width * scale, this.shadeTexture.Height * scale));
}
var isHover = ImGui.IsItemHovered();
if (isHover && (!shadeEasing.IsRunning || (shadeEasing.IsDone && shadeEasing.IsInverse)) && !inhibitFadeout)
@ -331,15 +333,15 @@ internal class TitleScreenMenuWindow : Window, IDisposable
}
// Drop shadow
ImGui.PushStyleColor(ImGuiCol.Text, 0xFF000000);
for (int i = 0, i_ = (int)Math.Ceiling(1 * scale); i < i_; i++)
using (ImRaii.PushColor(ImGuiCol.Text, 0xFF000000))
{
ImGui.SetCursorPos(new Vector2(cursor.X, cursor.Y + i));
ImGui.Text(entry.Name);
for (int i = 0, i_ = (int)Math.Ceiling(1 * scale); i < i_; i++)
{
ImGui.SetCursorPos(new Vector2(cursor.X, cursor.Y + i));
ImGui.Text(entry.Name);
}
}
ImGui.PopStyleColor();
ImGui.SetCursorPos(cursor);
ImGui.Text(entry.Name);

View file

@ -251,7 +251,7 @@ Thanks and have fun!";
new TextPayload(" ["),
new UIForegroundPayload(500),
this.openInstallerWindowPluginChangelogsLink,
new TextPayload(Loc.Localize("DalamudInstallerPluginChangelogHelp", "Open plugin changelogs") + " "),
new TextPayload(Loc.Localize("DalamudInstallerPluginChangelogHelp", "Open plugin changelogs")),
RawPayload.LinkTerminator,
new UIForegroundPayload(0),
new TextPayload("]"),
@ -262,13 +262,13 @@ Thanks and have fun!";
{
if (metadata.WasUpdated)
{
chatGui.Print(Locs.DalamudPluginUpdateSuccessful(metadata.Name, metadata.Version) + (metadata.HasChangelog ? " " : string.Empty));
chatGui.Print(Locs.DalamudPluginUpdateSuccessful(metadata.Name, metadata.Version));
}
else
{
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,
});
}

View file

@ -739,6 +739,11 @@ int main() {
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
have been loaded (invadeProcess=TRUE in SymInitialize() or SymRefreshModuleList())
@ -795,7 +800,11 @@ int main() {
std::wstring dumpError;
if (dumpPath.empty()) {
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{};
mdmp_info.ThreadId = GetThreadId(exinfo.hThreadHandle);
mdmp_info.ExceptionPointers = exinfo.pExceptionPointers;
@ -821,6 +830,10 @@ int main() {
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"Code: {:X}", exinfo.ExceptionRecord.ExceptionCode) << std::endl;
if (shutup)
log << L"======= Crash handler was globally muted(shutdown?) =======" << std::endl;
if (dumpPath.empty())
log << L"Dump skipped" << std::endl;
else if (dumpError.empty())
@ -971,6 +984,11 @@ int main() {
submitThread = {};
}
if (shutup) {
TerminateProcess(g_hProcess, exinfo.ExceptionRecord.ExceptionCode);
return 0;
}
int nButtonPressed = 0, nRadioButton = 0;
if (FAILED(TaskDialogIndirect(&config, &nButtonPressed, &nRadioButton, nullptr))) {
ResumeThread(exinfo.hThreadHandle);