From 616980f99faeac9e39840459074c888d07661602 Mon Sep 17 00:00:00 2001
From: goat <16760685+goaaats@users.noreply.github.com>
Date: Tue, 7 May 2024 20:40:09 +0200
Subject: [PATCH 01/13] build: 9.1.0.8
---
Dalamud/Dalamud.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index 364e8c90d..5abbac7cd 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -8,7 +8,7 @@
- 9.1.0.7
+ 9.1.0.8
XIV Launcher addon framework
$(DalamudVersion)
$(DalamudVersion)
From 48931dd8d22d2d3a5e9f1c74fe3dc9c6cadffb11 Mon Sep 17 00:00:00 2001
From: goat
Date: Wed, 8 May 2024 22:01:35 +0200
Subject: [PATCH 02/13] tab items must end conditionally Fixes random heap
corruption after opening the settings window
---
.../Windows/Settings/SettingsWindow.cs | 1 -
Dalamud/Interface/Utility/Raii/EndObjects.cs | 47 ++++++++-----------
2 files changed, 19 insertions(+), 29 deletions(-)
diff --git a/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs b/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs
index 2a8e6969a..99b51e122 100644
--- a/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs
@@ -158,7 +158,6 @@ internal class SettingsWindow : Window
}
ImGui.EndChild();
- ImGui.EndTabItem();
}
else if (settingsTab.IsOpen)
{
diff --git a/Dalamud/Interface/Utility/Raii/EndObjects.cs b/Dalamud/Interface/Utility/Raii/EndObjects.cs
index 3377b51bc..401af5415 100644
--- a/Dalamud/Interface/Utility/Raii/EndObjects.cs
+++ b/Dalamud/Interface/Utility/Raii/EndObjects.cs
@@ -109,40 +109,31 @@ public static partial class ImRaii
public static unsafe IEndObject TabItem(string label, ImGuiTabItemFlags flags)
{
+ ArgumentNullException.ThrowIfNull(label);
+
// One-off for now, we should make this into a generic solution if we need it more often
- const int ImGuiNET_Util_StackAllocationSizeLimit = 2048;
+ const int labelMaxAlloc = 2048;
- byte* native_label;
- int label_byteCount = 0;
- if (label != null)
+ var labelByteCount = Encoding.UTF8.GetByteCount(label);
+
+ if (labelByteCount > labelMaxAlloc)
{
- label_byteCount = Encoding.UTF8.GetByteCount(label);
-
- if (label_byteCount > ImGuiNET_Util_StackAllocationSizeLimit)
- {
- throw new ArgumentOutOfRangeException("label", "Label is too long. (Longer than 2048 bytes)");
- }
-
- byte* native_label_stackBytes = stackalloc byte[label_byteCount + 1];
- native_label = native_label_stackBytes;
-
- int native_label_offset;
- fixed (char* utf16Ptr = label)
- {
- native_label_offset = Encoding.UTF8.GetBytes(utf16Ptr, label.Length, native_label, label_byteCount);
- }
-
- native_label[native_label_offset] = 0;
- }
- else
- {
- native_label = null;
+ throw new ArgumentOutOfRangeException(nameof(label), $"Label is too long. (Longer than {labelMaxAlloc} bytes)");
}
- byte* p_open = null;
- byte ret = ImGuiNative.igBeginTabItem(native_label, p_open, flags);
+ var nativeLabelStackBytes = stackalloc byte[labelByteCount + 1];
- return new EndUnconditionally(ImGuiNative.igEndTabItem, ret != 0);
+ int nativeLabelOffset;
+ fixed (char* utf16Ptr = label)
+ {
+ nativeLabelOffset = Encoding.UTF8.GetBytes(utf16Ptr, label.Length, nativeLabelStackBytes, labelByteCount);
+ }
+
+ nativeLabelStackBytes[nativeLabelOffset] = 0;
+
+ var ret = ImGuiNative.igBeginTabItem(nativeLabelStackBytes, null, flags);
+
+ return new EndConditionally(ImGuiNative.igEndTabItem, ret != 0);
}
public static IEndObject TabItem(string label, ref bool open)
From a355ba863b794ee53a4903628da92702aaf54640 Mon Sep 17 00:00:00 2001
From: goat
Date: Wed, 8 May 2024 22:20:27 +0200
Subject: [PATCH 03/13] build: 9.1.0.9
---
Dalamud/Dalamud.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index 5abbac7cd..e8ec785b8 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -8,7 +8,7 @@
- 9.1.0.8
+ 9.1.0.9
XIV Launcher addon framework
$(DalamudVersion)
$(DalamudVersion)
From 9f32b055871297090288926abf2c99bcf493377d Mon Sep 17 00:00:00 2001
From: goat
Date: Thu, 9 May 2024 00:43:16 +0200
Subject: [PATCH 04/13] settings: properly EndChild
---
.../Windows/Settings/SettingsWindow.cs | 47 ++++++++++---------
.../Windows/Settings/Tabs/SettingsTabAbout.cs | 6 +--
2 files changed, 27 insertions(+), 26 deletions(-)
diff --git a/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs b/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs
index 99b51e122..fd4949533 100644
--- a/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs
@@ -152,12 +152,12 @@ internal class SettingsWindow : Window
settingsTab.OnOpen();
}
- if (ImGui.BeginChild($"###settings_scrolling_{settingsTab.Title}", new Vector2(-1, -1), false))
- {
+ using var tabChild = ImRaii.Child(
+ $"###settings_scrolling_{settingsTab.Title}",
+ new Vector2(-1, -1),
+ false);
+ if (tabChild)
settingsTab.Draw();
- }
-
- ImGui.EndChild();
}
else if (settingsTab.IsOpen)
{
@@ -207,33 +207,34 @@ internal class SettingsWindow : Window
ImGui.SetCursorPos(windowSize - ImGuiHelpers.ScaledVector2(70));
- if (ImGui.BeginChild("###settingsFinishButton"))
+ using (var buttonChild = ImRaii.Child("###settingsFinishButton"))
{
- using var disabled = ImRaii.Disabled(this.tabs.Any(x => x.Entries.Any(y => !y.IsValid)));
-
- using (ImRaii.PushStyle(ImGuiStyleVar.FrameRounding, 100f))
+ if (buttonChild)
{
- using var font = ImRaii.PushFont(InterfaceManager.IconFont);
+ using var disabled = ImRaii.Disabled(this.tabs.Any(x => x.Entries.Any(y => !y.IsValid)));
- 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;
+ }
+ }
+
+ if (ImGui.IsItemHovered())
+ {
+ ImGui.SetTooltip(!ImGui.IsKeyDown(ImGuiKey.ModShift)
+ ? Loc.Localize("DalamudSettingsSaveAndExit", "Save changes and close")
+ : Loc.Localize("DalamudSettingsSave", "Save changes"));
}
}
-
- if (ImGui.IsItemHovered())
- {
- ImGui.SetTooltip(!ImGui.IsKeyDown(ImGuiKey.ModShift)
- ? Loc.Localize("DalamudSettingsSaveAndExit", "Save changes and close")
- : Loc.Localize("DalamudSettingsSave", "Save changes"));
- }
}
- 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);
diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAbout.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAbout.cs
index 8714fd666..d38f9219d 100644
--- a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAbout.cs
+++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAbout.cs
@@ -234,7 +234,9 @@ Contribute at: https://github.com/goatcorp/Dalamud
{
var windowSize = ImGui.GetWindowSize();
- ImGui.BeginChild("scrolling", Vector2.Zero, false, ImGuiWindowFlags.NoScrollbar);
+ using var child = ImRaii.Child("scrolling", new Vector2(-1, -10 * ImGuiHelpers.GlobalScale), false, ImGuiWindowFlags.NoScrollbar);
+ if (!child)
+ return;
if (this.resetNow)
{
@@ -295,8 +297,6 @@ Contribute at: https://github.com/goatcorp/Dalamud
}
}
- ImGui.EndChild();
-
base.Draw();
}
From 913d4732b5c64ead4aedb888d006a94cda006d9f Mon Sep 17 00:00:00 2001
From: goat
Date: Tue, 14 May 2024 00:27:11 +0200
Subject: [PATCH 05/13] don't write to the manifest when reloading dev
plugins(fixes #1328) genericizes the way WorkingPluginId is accessed away
from the manifest, since we probably don't want to have it there in the
future for regular plugins either
---
.../Game/Addon/Events/AddonEventManager.cs | 8 ++--
.../PluginInstaller/PluginInstallerWindow.cs | 36 ++++++++--------
.../PluginInstaller/ProfileManagerWidget.cs | 6 +--
Dalamud/Plugin/DalamudPluginInterface.cs | 4 +-
Dalamud/Plugin/Internal/PluginManager.cs | 30 +++++++-------
.../Internal/Profiles/ProfileManager.cs | 6 +--
.../Plugin/Internal/Types/LocalDevPlugin.cs | 30 ++++++++++----
Dalamud/Plugin/Internal/Types/LocalPlugin.cs | 41 ++++++++-----------
8 files changed, 82 insertions(+), 79 deletions(-)
diff --git a/Dalamud/Game/Addon/Events/AddonEventManager.cs b/Dalamud/Game/Addon/Events/AddonEventManager.cs
index a9b9ef5fa..8af02ba70 100644
--- a/Dalamud/Game/Addon/Events/AddonEventManager.cs
+++ b/Dalamud/Game/Addon/Events/AddonEventManager.cs
@@ -221,7 +221,7 @@ internal class AddonEventManagerPluginScoped : IInternalDisposableService, IAddo
{
this.plugin = plugin;
- this.eventManagerService.AddPluginEventController(plugin.Manifest.WorkingPluginId);
+ this.eventManagerService.AddPluginEventController(plugin.EffectiveWorkingPluginId);
}
///
@@ -233,16 +233,16 @@ internal class AddonEventManagerPluginScoped : IInternalDisposableService, IAddo
this.eventManagerService.ResetCursor();
}
- this.eventManagerService.RemovePluginEventController(this.plugin.Manifest.WorkingPluginId);
+ this.eventManagerService.RemovePluginEventController(this.plugin.EffectiveWorkingPluginId);
}
///
public IAddonEventHandle? AddEvent(IntPtr atkUnitBase, IntPtr atkResNode, AddonEventType eventType, IAddonEventManager.AddonEventHandler eventHandler)
- => this.eventManagerService.AddEvent(this.plugin.Manifest.WorkingPluginId, atkUnitBase, atkResNode, eventType, eventHandler);
+ => this.eventManagerService.AddEvent(this.plugin.EffectiveWorkingPluginId, atkUnitBase, atkResNode, eventType, eventHandler);
///
public void RemoveEvent(IAddonEventHandle eventHandle)
- => this.eventManagerService.RemoveEvent(this.plugin.Manifest.WorkingPluginId, eventHandle);
+ => this.eventManagerService.RemoveEvent(this.plugin.EffectiveWorkingPluginId, eventHandle);
///
public void SetCursor(AddonCursorType cursor)
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
index 40fa852cd..a4efb1f5e 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
@@ -2438,7 +2438,7 @@ internal class PluginInstallerWindow : Window, IDisposable
if (this.hasDevPlugins)
{
ImGuiHelpers.ScaledDummy(3);
- ImGui.TextColored(ImGuiColors.DalamudGrey, $"WorkingPluginId: {manifest.WorkingPluginId}");
+ ImGui.TextColored(ImGuiColors.DalamudGrey, $"WorkingPluginId: {plugin.EffectiveWorkingPluginId}");
ImGuiHelpers.ScaledDummy(3);
}
@@ -2621,10 +2621,10 @@ internal class PluginInstallerWindow : Window, IDisposable
var applicableForProfiles = plugin.Manifest.SupportsProfiles /*&& !plugin.IsDev*/;
var profilesThatWantThisPlugin = profileManager.Profiles
- .Where(x => x.WantsPlugin(plugin.Manifest.WorkingPluginId) != null)
+ .Where(x => x.WantsPlugin(plugin.EffectiveWorkingPluginId) != null)
.ToArray();
var isInSingleProfile = profilesThatWantThisPlugin.Length == 1;
- var isDefaultPlugin = profileManager.IsInDefaultProfile(plugin.Manifest.WorkingPluginId);
+ var isDefaultPlugin = profileManager.IsInDefaultProfile(plugin.EffectiveWorkingPluginId);
// Disable everything if the updater is running or another plugin is operating
var disabled = this.updateStatus == OperationStatus.InProgress || this.installStatus == OperationStatus.InProgress;
@@ -2659,17 +2659,17 @@ internal class PluginInstallerWindow : Window, IDisposable
foreach (var profile in profileManager.Profiles.Where(x => !x.IsDefaultProfile))
{
- var inProfile = profile.WantsPlugin(plugin.Manifest.WorkingPluginId) != null;
+ var inProfile = profile.WantsPlugin(plugin.EffectiveWorkingPluginId) != null;
if (ImGui.Checkbox($"###profilePick{profile.Guid}{plugin.Manifest.InternalName}", ref inProfile))
{
if (inProfile)
{
- Task.Run(() => profile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, plugin.Manifest.InternalName, true))
+ Task.Run(() => profile.AddOrUpdateAsync(plugin.EffectiveWorkingPluginId, plugin.Manifest.InternalName, true))
.ContinueWith(this.DisplayErrorContinuation, Locs.Profiles_CouldNotAdd);
}
else
{
- Task.Run(() => profile.RemoveAsync(plugin.Manifest.WorkingPluginId))
+ Task.Run(() => profile.RemoveAsync(plugin.EffectiveWorkingPluginId))
.ContinueWith(this.DisplayErrorContinuation, Locs.Profiles_CouldNotRemove);
}
}
@@ -2689,11 +2689,11 @@ internal class PluginInstallerWindow : Window, IDisposable
if (ImGuiComponents.IconButton(FontAwesomeIcon.Times))
{
// TODO: Work this out
- Task.Run(() => profileManager.DefaultProfile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, plugin.Manifest.InternalName, plugin.IsLoaded, false))
+ Task.Run(() => profileManager.DefaultProfile.AddOrUpdateAsync(plugin.EffectiveWorkingPluginId, plugin.Manifest.InternalName, plugin.IsLoaded, false))
.GetAwaiter().GetResult();
foreach (var profile in profileManager.Profiles.Where(x => !x.IsDefaultProfile && x.Plugins.Any(y => y.InternalName == plugin.Manifest.InternalName)))
{
- Task.Run(() => profile.RemoveAsync(plugin.Manifest.WorkingPluginId, false))
+ Task.Run(() => profile.RemoveAsync(plugin.EffectiveWorkingPluginId, false))
.GetAwaiter().GetResult();
}
@@ -2718,7 +2718,7 @@ internal class PluginInstallerWindow : Window, IDisposable
if (ImGui.IsItemHovered())
ImGui.SetTooltip(Locs.PluginButtonToolTip_UnloadFailed);
}
- else if (this.enableDisableStatus == OperationStatus.InProgress && this.enableDisableWorkingPluginId == plugin.Manifest.WorkingPluginId)
+ else if (this.enableDisableStatus == OperationStatus.InProgress && this.enableDisableWorkingPluginId == plugin.EffectiveWorkingPluginId)
{
ImGuiComponents.DisabledToggleButton(toggleId, this.loadingIndicatorKind == LoadingIndicatorKind.EnablingSingle);
}
@@ -2743,9 +2743,9 @@ internal class PluginInstallerWindow : Window, IDisposable
{
// Reload the devPlugin manifest if it's a dev plugin
// The plugin might rely on changed values in the manifest
- if (plugin.IsDev)
+ if (plugin is LocalDevPlugin devPlugin)
{
- plugin.ReloadManifest();
+ devPlugin.ReloadManifest();
}
}
catch (Exception ex)
@@ -2761,13 +2761,13 @@ internal class PluginInstallerWindow : Window, IDisposable
{
this.enableDisableStatus = OperationStatus.InProgress;
this.loadingIndicatorKind = LoadingIndicatorKind.DisablingSingle;
- this.enableDisableWorkingPluginId = plugin.Manifest.WorkingPluginId;
+ this.enableDisableWorkingPluginId = plugin.EffectiveWorkingPluginId;
Task.Run(async () =>
{
await plugin.UnloadAsync();
await applicableProfile.AddOrUpdateAsync(
- plugin.Manifest.WorkingPluginId, plugin.Manifest.InternalName, false, false);
+ plugin.EffectiveWorkingPluginId, plugin.Manifest.InternalName, false, false);
notifications.AddNotification(Locs.Notifications_PluginDisabled(plugin.Manifest.Name), Locs.Notifications_PluginDisabledTitle, NotificationType.Success);
}).ContinueWith(t =>
@@ -2782,9 +2782,9 @@ internal class PluginInstallerWindow : Window, IDisposable
{
this.enableDisableStatus = OperationStatus.InProgress;
this.loadingIndicatorKind = LoadingIndicatorKind.EnablingSingle;
- this.enableDisableWorkingPluginId = plugin.Manifest.WorkingPluginId;
+ this.enableDisableWorkingPluginId = plugin.EffectiveWorkingPluginId;
- await applicableProfile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, plugin.Manifest.InternalName, true, false);
+ await applicableProfile.AddOrUpdateAsync(plugin.EffectiveWorkingPluginId, plugin.Manifest.InternalName, true, false);
await plugin.LoadAsync(PluginLoadReason.Installer);
notifications.AddNotification(Locs.Notifications_PluginEnabled(plugin.Manifest.Name), Locs.Notifications_PluginEnabledTitle, NotificationType.Success);
@@ -2805,7 +2805,7 @@ internal class PluginInstallerWindow : Window, IDisposable
if (shouldUpdate)
{
// We need to update the profile right here, because PM will not enable the plugin otherwise
- await applicableProfile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, plugin.Manifest.InternalName, true, false);
+ await applicableProfile.AddOrUpdateAsync(plugin.EffectiveWorkingPluginId, plugin.Manifest.InternalName, true, false);
await this.UpdateSinglePlugin(availableUpdate);
}
else
@@ -3076,7 +3076,7 @@ internal class PluginInstallerWindow : Window, IDisposable
if (localPlugin is LocalDevPlugin plugin)
{
var isInDefaultProfile =
- Service.Get().IsInDefaultProfile(localPlugin.Manifest.WorkingPluginId);
+ Service.Get().IsInDefaultProfile(localPlugin.EffectiveWorkingPluginId);
// https://colorswall.com/palette/2868/
var greenColor = new Vector4(0x5C, 0xB8, 0x5C, 0xFF) / 0xFF;
@@ -3426,7 +3426,7 @@ internal class PluginInstallerWindow : Window, IDisposable
this.pluginListAvailable.Sort((p1, p2) => p1.Name.CompareTo(p2.Name));
var profman = Service.Get();
- this.pluginListInstalled.Sort((p1, p2) => profman.IsInDefaultProfile(p1.Manifest.WorkingPluginId).CompareTo(profman.IsInDefaultProfile(p2.Manifest.WorkingPluginId)));
+ this.pluginListInstalled.Sort((p1, p2) => profman.IsInDefaultProfile(p1.EffectiveWorkingPluginId).CompareTo(profman.IsInDefaultProfile(p2.EffectiveWorkingPluginId)));
break;
default:
throw new InvalidEnumArgumentException("Unknown plugin sort type.");
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs
index cac249abd..d0dc01ce5 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs
@@ -324,7 +324,7 @@ internal class ProfileManagerWidget
if (ImGui.Selectable($"{plugin.Manifest.Name}{(plugin is LocalDevPlugin ? "(dev plugin)" : string.Empty)}###selector{plugin.Manifest.InternalName}"))
{
- Task.Run(() => profile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, plugin.Manifest.InternalName, true, false))
+ Task.Run(() => profile.AddOrUpdateAsync(plugin.EffectiveWorkingPluginId, plugin.Manifest.InternalName, true, false))
.ContinueWith(this.installer.DisplayErrorContinuation, Locs.ErrorCouldNotChangeState);
}
}
@@ -430,7 +430,7 @@ internal class ProfileManagerWidget
foreach (var profileEntry in profile.Plugins.ToArray())
{
didAny = true;
- var pmPlugin = pm.InstalledPlugins.FirstOrDefault(x => x.Manifest.WorkingPluginId == profileEntry.WorkingPluginId);
+ var pmPlugin = pm.InstalledPlugins.FirstOrDefault(x => x.EffectiveWorkingPluginId == profileEntry.WorkingPluginId);
var btnOffset = 2;
if (pmPlugin != null)
@@ -485,7 +485,7 @@ internal class ProfileManagerWidget
FontAwesomeIcon.Check,
"Yes, use this one"))
{
- profileEntry.WorkingPluginId = firstAvailableInstalled.Manifest.WorkingPluginId;
+ profileEntry.WorkingPluginId = firstAvailableInstalled.EffectiveWorkingPluginId;
Task.Run(async () =>
{
await profman.ApplyAllWantStatesAsync();
diff --git a/Dalamud/Plugin/DalamudPluginInterface.cs b/Dalamud/Plugin/DalamudPluginInterface.cs
index 7e224919a..d53c620f4 100644
--- a/Dalamud/Plugin/DalamudPluginInterface.cs
+++ b/Dalamud/Plugin/DalamudPluginInterface.cs
@@ -398,7 +398,7 @@ public sealed class DalamudPluginInterface : IDisposable
if (currentConfig == null)
return;
- this.configs.Save(currentConfig, this.plugin.InternalName, this.plugin.Manifest.WorkingPluginId);
+ this.configs.Save(currentConfig, this.plugin.InternalName, this.plugin.EffectiveWorkingPluginId);
}
///
@@ -425,7 +425,7 @@ public sealed class DalamudPluginInterface : IDisposable
}
// this shouldn't be a thing, I think, but just in case
- return this.configs.Load(this.plugin.InternalName, this.plugin.Manifest.WorkingPluginId);
+ return this.configs.Load(this.plugin.InternalName, this.plugin.EffectiveWorkingPluginId);
}
///
diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs
index d64a3b9b0..7517ae413 100644
--- a/Dalamud/Plugin/Internal/PluginManager.cs
+++ b/Dalamud/Plugin/Internal/PluginManager.cs
@@ -1029,7 +1029,7 @@ internal class PluginManager : IInternalDisposableService
{
var plugin = metadata.InstalledPlugin;
- var workingPluginId = metadata.InstalledPlugin.Manifest.WorkingPluginId;
+ var workingPluginId = metadata.InstalledPlugin.EffectiveWorkingPluginId;
if (workingPluginId == Guid.Empty)
throw new Exception("Existing plugin had no WorkingPluginId");
@@ -1331,16 +1331,16 @@ internal class PluginManager : IInternalDisposableService
foreach (var installedPlugin in this.InstalledPlugins)
{
- if (installedPlugin.Manifest.WorkingPluginId == Guid.Empty)
+ if (installedPlugin.EffectiveWorkingPluginId == Guid.Empty)
throw new Exception($"{(installedPlugin is LocalDevPlugin ? "DevPlugin" : "Plugin")} '{installedPlugin.Manifest.InternalName}' has an empty WorkingPluginId.");
- if (seenIds.Contains(installedPlugin.Manifest.WorkingPluginId))
+ if (seenIds.Contains(installedPlugin.EffectiveWorkingPluginId))
{
throw new Exception(
- $"{(installedPlugin is LocalDevPlugin ? "DevPlugin" : "Plugin")} '{installedPlugin.Manifest.InternalName}' has a duplicate WorkingPluginId '{installedPlugin.Manifest.WorkingPluginId}'");
+ $"{(installedPlugin is LocalDevPlugin ? "DevPlugin" : "Plugin")} '{installedPlugin.Manifest.InternalName}' has a duplicate WorkingPluginId '{installedPlugin.EffectiveWorkingPluginId}'");
}
- seenIds.Add(installedPlugin.Manifest.WorkingPluginId);
+ seenIds.Add(installedPlugin.EffectiveWorkingPluginId);
}
this.profileManager.ParanoiaValidateProfiles();
@@ -1388,7 +1388,7 @@ internal class PluginManager : IInternalDisposableService
{
// Only remove entries from the default profile that are NOT currently tied to an active LocalPlugin
var guidsToRemove = this.profileManager.DefaultProfile.Plugins
- .Where(x => this.InstalledPlugins.All(y => y.Manifest.WorkingPluginId != x.WorkingPluginId))
+ .Where(x => this.InstalledPlugins.All(y => y.EffectiveWorkingPluginId != x.WorkingPluginId))
.Select(x => x.WorkingPluginId)
.ToArray();
@@ -1560,9 +1560,9 @@ internal class PluginManager : IInternalDisposableService
// This will also happen if you are installing a plugin with the installer, and that's intended!
// It means that, if you have a profile which has unsatisfied plugins, installing a matching plugin will
// enter it into the profiles it can match.
- if (plugin.Manifest.WorkingPluginId == Guid.Empty)
+ if (plugin.EffectiveWorkingPluginId == Guid.Empty)
throw new Exception("Plugin should have a WorkingPluginId at this point");
- this.profileManager.MigrateProfilesToGuidsForPlugin(plugin.Manifest.InternalName, plugin.Manifest.WorkingPluginId);
+ this.profileManager.MigrateProfilesToGuidsForPlugin(plugin.Manifest.InternalName, plugin.EffectiveWorkingPluginId);
var wantedByAnyProfile = false;
@@ -1573,7 +1573,7 @@ internal class PluginManager : IInternalDisposableService
loadPlugin &= !isBoot;
var wantsInDefaultProfile =
- this.profileManager.DefaultProfile.WantsPlugin(plugin.Manifest.WorkingPluginId);
+ this.profileManager.DefaultProfile.WantsPlugin(plugin.EffectiveWorkingPluginId);
if (wantsInDefaultProfile == null)
{
// We don't know about this plugin, so we don't want to do anything here.
@@ -1582,7 +1582,7 @@ internal class PluginManager : IInternalDisposableService
// Check if any profile wants this plugin. We need to do this here, since we want to allow loading a dev plugin if a non-default profile wants it active.
// Note that this will not add the plugin to the default profile. That's done below in any other case.
- wantedByAnyProfile = await this.profileManager.GetWantStateAsync(plugin.Manifest.WorkingPluginId, plugin.Manifest.InternalName, false, false);
+ wantedByAnyProfile = await this.profileManager.GetWantStateAsync(plugin.EffectiveWorkingPluginId, plugin.Manifest.InternalName, false, false);
// If it is wanted by any other profile, we do want to load it.
if (wantedByAnyProfile)
@@ -1592,28 +1592,28 @@ internal class PluginManager : IInternalDisposableService
{
// We didn't want this plugin, and StartOnBoot is on. That means we don't want it and it should stay off until manually enabled.
Log.Verbose("DevPlugin {Name} disabled and StartOnBoot => disable", plugin.Manifest.InternalName);
- await this.profileManager.DefaultProfile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, plugin.Manifest.InternalName, false, false);
+ await this.profileManager.DefaultProfile.AddOrUpdateAsync(plugin.EffectiveWorkingPluginId, plugin.Manifest.InternalName, false, false);
loadPlugin = false;
}
else if (wantsInDefaultProfile == true && devPlugin.StartOnBoot)
{
// We wanted this plugin, and StartOnBoot is on. That means we actually do want it.
Log.Verbose("DevPlugin {Name} enabled and StartOnBoot => enable", plugin.Manifest.InternalName);
- await this.profileManager.DefaultProfile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, plugin.Manifest.InternalName, true, false);
+ await this.profileManager.DefaultProfile.AddOrUpdateAsync(plugin.EffectiveWorkingPluginId, plugin.Manifest.InternalName, true, false);
loadPlugin = !doNotLoad;
}
else if (wantsInDefaultProfile == true && !devPlugin.StartOnBoot)
{
// We wanted this plugin, but StartOnBoot is off. This means we don't want it anymore.
Log.Verbose("DevPlugin {Name} enabled and !StartOnBoot => disable", plugin.Manifest.InternalName);
- await this.profileManager.DefaultProfile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, plugin.Manifest.InternalName, false, false);
+ await this.profileManager.DefaultProfile.AddOrUpdateAsync(plugin.EffectiveWorkingPluginId, plugin.Manifest.InternalName, false, false);
loadPlugin = false;
}
else if (wantsInDefaultProfile == false && !devPlugin.StartOnBoot)
{
// We didn't want this plugin, and StartOnBoot is off. We don't want it.
Log.Verbose("DevPlugin {Name} disabled and !StartOnBoot => disable", plugin.Manifest.InternalName);
- await this.profileManager.DefaultProfile.AddOrUpdateAsync(plugin.Manifest.WorkingPluginId, plugin.Manifest.InternalName, false, false);
+ await this.profileManager.DefaultProfile.AddOrUpdateAsync(plugin.EffectiveWorkingPluginId, plugin.Manifest.InternalName, false, false);
loadPlugin = false;
}
@@ -1626,7 +1626,7 @@ internal class PluginManager : IInternalDisposableService
// Plugins that aren't in any profile will be added to the default profile with this call.
// We are skipping a double-lookup for dev plugins that are wanted by non-default profiles, as noted above.
- wantedByAnyProfile = wantedByAnyProfile || await this.profileManager.GetWantStateAsync(plugin.Manifest.WorkingPluginId, plugin.Manifest.InternalName, defaultState);
+ wantedByAnyProfile = wantedByAnyProfile || await this.profileManager.GetWantStateAsync(plugin.EffectiveWorkingPluginId, plugin.Manifest.InternalName, defaultState);
Log.Information("{Name} defaultState: {State} wantedByAnyProfile: {WantedByAny} loadPlugin: {LoadPlugin}", plugin.Manifest.InternalName, defaultState, wantedByAnyProfile, loadPlugin);
if (loadPlugin)
diff --git a/Dalamud/Plugin/Internal/Profiles/ProfileManager.cs b/Dalamud/Plugin/Internal/Profiles/ProfileManager.cs
index d9c5ac787..e36e9908b 100644
--- a/Dalamud/Plugin/Internal/Profiles/ProfileManager.cs
+++ b/Dalamud/Plugin/Internal/Profiles/ProfileManager.cs
@@ -183,8 +183,8 @@ internal class ProfileManager : IServiceType
var installedPlugin = pm.InstalledPlugins.FirstOrDefault(x => x.Manifest.InternalName == plugin.InternalName);
if (installedPlugin != null)
{
- Log.Information("Satisfying plugin {InternalName} for profile {Name} with {Guid}", plugin.InternalName, newModel.Name, installedPlugin.Manifest.WorkingPluginId);
- plugin.WorkingPluginId = installedPlugin.Manifest.WorkingPluginId;
+ Log.Information("Satisfying plugin {InternalName} for profile {Name} with {Guid}", plugin.InternalName, newModel.Name, installedPlugin.EffectiveWorkingPluginId);
+ plugin.WorkingPluginId = installedPlugin.EffectiveWorkingPluginId;
}
else
{
@@ -237,7 +237,7 @@ internal class ProfileManager : IServiceType
var pm = Service.Get();
foreach (var installedPlugin in pm.InstalledPlugins)
{
- var wantThis = wantActive.Any(x => x.WorkingPluginId == installedPlugin.Manifest.WorkingPluginId);
+ var wantThis = wantActive.Any(x => x.WorkingPluginId == installedPlugin.EffectiveWorkingPluginId);
switch (wantThis)
{
case true when !installedPlugin.IsLoaded:
diff --git a/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs
index ab7b86021..f5fdbc663 100644
--- a/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs
+++ b/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs
@@ -50,14 +50,6 @@ internal class LocalDevPlugin : LocalPlugin, IDisposable
Log.Verbose("{InternalName} was assigned new devPlugin GUID {Guid}", this.InternalName, this.devSettings.WorkingPluginId);
configuration.QueueSave();
}
-
- // If the ID in the manifest is wrong, force the good one
- if (this.DevImposedWorkingPluginId != this.manifest.WorkingPluginId)
- {
- Debug.Assert(this.DevImposedWorkingPluginId != Guid.Empty, "Empty guid for devPlugin");
- this.manifest.WorkingPluginId = this.DevImposedWorkingPluginId;
- this.SaveManifest("dev imposed working plugin id");
- }
if (this.AutomaticReload)
{
@@ -99,7 +91,10 @@ internal class LocalDevPlugin : LocalPlugin, IDisposable
/// Gets an ID uniquely identifying this specific instance of a devPlugin.
///
public Guid DevImposedWorkingPluginId => this.devSettings.WorkingPluginId;
-
+
+ ///
+ public override Guid EffectiveWorkingPluginId => this.DevImposedWorkingPluginId;
+
///
/// Gets a list of validation problems that have been dismissed by the user.
///
@@ -148,6 +143,23 @@ internal class LocalDevPlugin : LocalPlugin, IDisposable
}
}
+ ///
+ /// Reload the manifest if it exists, to update possible changes.
+ ///
+ /// Thrown if the manifest could not be loaded.
+ public void ReloadManifest()
+ {
+ var manifestPath = LocalPluginManifest.GetManifestFile(this.DllFile);
+ if (manifestPath.Exists)
+ this.manifest = LocalPluginManifest.Load(manifestPath) ?? throw new Exception("Could not reload manifest.");
+ }
+
+ ///
+ protected override void OnPreReload()
+ {
+ this.ReloadManifest();
+ }
+
private void OnFileChanged(object sender, FileSystemEventArgs args)
{
var current = Interlocked.Increment(ref this.reloadCounter);
diff --git a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs
index bca02a927..227a6c707 100644
--- a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs
+++ b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs
@@ -91,7 +91,7 @@ internal class LocalPlugin : IDisposable
}
// Create an installation instance ID for this plugin, if it doesn't have one yet
- if (this.manifest.WorkingPluginId == Guid.Empty)
+ if (this.manifest.WorkingPluginId == Guid.Empty && !this.IsDev)
{
this.manifest.WorkingPluginId = Guid.NewGuid();
@@ -162,7 +162,7 @@ internal class LocalPlugin : IDisposable
/// INCLUDES the default profile.
///
public bool IsWantedByAnyProfile =>
- Service.Get().GetWantStateAsync(this.manifest.WorkingPluginId, this.Manifest.InternalName, false, false).GetAwaiter().GetResult();
+ Service.Get().GetWantStateAsync(this.EffectiveWorkingPluginId, this.Manifest.InternalName, false, false).GetAwaiter().GetResult();
///
/// Gets a value indicating whether this plugin's API level is out of date.
@@ -215,6 +215,11 @@ internal class LocalPlugin : IDisposable
///
public Version EffectiveVersion => this.manifest.EffectiveVersion;
+ ///
+ /// Gets the effective working plugin ID for this plugin.
+ ///
+ public virtual Guid EffectiveWorkingPluginId => this.manifest.WorkingPluginId;
+
///
/// Gets the service scope for this plugin.
///
@@ -271,11 +276,8 @@ internal class LocalPlugin : IDisposable
await this.pluginLoadStateLock.WaitAsync();
try
{
- if (reloading && this.IsDev)
- {
- // Reload the manifest in-case there were changes here too.
- this.ReloadManifest();
- }
+ if (reloading)
+ this.OnPreReload();
// If we reload a plugin we don't want to delete it. Makes sense, right?
if (this.manifest.ScheduledForDeletion)
@@ -578,24 +580,6 @@ internal class LocalPlugin : IDisposable
this.SaveManifest("scheduling for deletion");
}
- ///
- /// Reload the manifest if it exists, preserve the internal Disabled state.
- ///
- public void ReloadManifest()
- {
- var manifestPath = LocalPluginManifest.GetManifestFile(this.DllFile);
- if (manifestPath.Exists)
- {
- // Save some state that we do actually want to carry over
- var guid = this.manifest.WorkingPluginId;
-
- this.manifest = LocalPluginManifest.Load(manifestPath) ?? throw new Exception("Could not reload manifest.");
- this.manifest.WorkingPluginId = guid;
-
- this.SaveManifest("dev reload");
- }
- }
-
///
/// Get the repository this plugin was installed from.
///
@@ -620,6 +604,13 @@ internal class LocalPlugin : IDisposable
///
/// Why it should be saved.
protected void SaveManifest(string reason) => this.manifest.Save(this.manifestFile, reason);
+
+ ///
+ /// Called before a plugin is reloaded.
+ ///
+ protected virtual void OnPreReload()
+ {
+ }
private static void SetupLoaderConfig(LoaderConfig config)
{
From dcc8018393956f45298c764804d95d916e194de5 Mon Sep 17 00:00:00 2001
From: bleatbot <106497096+bleatbot@users.noreply.github.com>
Date: Sun, 19 May 2024 20:18:54 +0200
Subject: [PATCH 06/13] Update ClientStructs (#1805)
Co-authored-by: github-actions[bot]
---
lib/FFXIVClientStructs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs
index b7a834e78..bb1530c9c 160000
--- a/lib/FFXIVClientStructs
+++ b/lib/FFXIVClientStructs
@@ -1 +1 @@
-Subproject commit b7a834e78fd7250023c3f70c5717c28b01d18acc
+Subproject commit bb1530c9c74ca35b7edb0a13d79676a4950832c7
From eca40bc5dde200abe7bf377f3c314a538369db3f Mon Sep 17 00:00:00 2001
From: bleatbot <106497096+bleatbot@users.noreply.github.com>
Date: Sun, 19 May 2024 20:43:51 +0200
Subject: [PATCH 07/13] Update ClientStructs (#1810)
Co-authored-by: github-actions[bot]
---
lib/FFXIVClientStructs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs
index bb1530c9c..29dfda5cd 160000
--- a/lib/FFXIVClientStructs
+++ b/lib/FFXIVClientStructs
@@ -1 +1 @@
-Subproject commit bb1530c9c74ca35b7edb0a13d79676a4950832c7
+Subproject commit 29dfda5cd439ce602e18630c22c2d1a5e2c094ec
From 0a219fcd82fafe4fb7b7f132006a72fdb01dd668 Mon Sep 17 00:00:00 2001
From: srkizer
Date: Tue, 21 May 2024 15:41:25 +0900
Subject: [PATCH 08/13] Add IME state indicator opacity setting (#1811)
---
.../Internal/DalamudConfiguration.cs | 6 ++
Dalamud/Interface/Internal/DalamudIme.cs | 82 ++++++++++++-------
.../Windows/Settings/Tabs/SettingsTabLook.cs | 22 +++++
.../Settings/Widgets/SettingsEntry{T}.cs | 21 ++++-
4 files changed, 99 insertions(+), 32 deletions(-)
diff --git a/Dalamud/Configuration/Internal/DalamudConfiguration.cs b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
index 2e9e9df48..67c220800 100644
--- a/Dalamud/Configuration/Internal/DalamudConfiguration.cs
+++ b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
@@ -162,6 +162,12 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
[Obsolete("It happens that nobody touched this setting", true)]
public float FontGammaLevel { get; set; } = 1.4f;
+ /// Gets or sets the opacity of the IME state indicator.
+ /// 0 will hide the state indicator. 1 will make the state indicator fully visible. Values outside the
+ /// range will be clamped to [0, 1].
+ /// See to .
+ public float ImeStateIndicatorOpacity { get; set; } = 1f;
+
///
/// Gets or sets a value indicating whether or not plugin UI should be hidden.
///
diff --git a/Dalamud/Interface/Internal/DalamudIme.cs b/Dalamud/Interface/Internal/DalamudIme.cs
index 61ec24484..c061ec12d 100644
--- a/Dalamud/Interface/Internal/DalamudIme.cs
+++ b/Dalamud/Interface/Internal/DalamudIme.cs
@@ -11,6 +11,7 @@ using System.Runtime.InteropServices;
using System.Text;
using System.Text.Unicode;
+using Dalamud.Configuration.Internal;
using Dalamud.Game.Text;
using Dalamud.Hooking.WndProcHook;
using Dalamud.Interface.Colors;
@@ -74,6 +75,9 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
private static readonly delegate* unmanaged StbTextUndo;
+ [ServiceManager.ServiceDependency]
+ private readonly DalamudConfiguration dalamudConfiguration = Service.Get();
+
[ServiceManager.ServiceDependency]
private readonly WndProcHookManager wndProcHookManager = Service.Get();
@@ -774,30 +778,42 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
ImGui.GetStyle().WindowRounding);
}
+ var stateOpacity = Math.Clamp(this.dalamudConfiguration.ImeStateIndicatorOpacity, 0, 1);
+ var stateBg = ImGui.GetColorU32(
+ new Vector4(1, 1, 1, MathF.Pow(stateOpacity, 2)) * *ImGui.GetStyleColorVec4(ImGuiCol.WindowBg));
+ var stateFg =
+ ImGui.GetColorU32(new Vector4(1, 1, 1, stateOpacity) * *ImGui.GetStyleColorVec4(ImGuiCol.Text));
if (!expandUpward && drawIme)
{
- for (var dx = -2; dx <= 2; dx++)
+ if (stateBg >= 0x1000000)
{
- for (var dy = -2; dy <= 2; dy++)
+ for (var dx = -2; dx <= 2; dx++)
{
- if (dx != 0 || dy != 0)
+ for (var dy = -2; dy <= 2; dy++)
{
- imeIconFont.RenderChar(
- drawList,
- imeIconFont.FontSize,
- cursor + new Vector2(dx, dy),
- ImGui.GetColorU32(ImGuiCol.WindowBg),
- ime.inputModeIcon);
+ if (dx != 0 || dy != 0)
+ {
+ imeIconFont.RenderChar(
+ drawList,
+ imeIconFont.FontSize,
+ cursor + new Vector2(dx, dy),
+ stateBg,
+ ime.inputModeIcon);
+ }
}
}
}
- imeIconFont.RenderChar(
- drawList,
- imeIconFont.FontSize,
- cursor,
- ImGui.GetColorU32(ImGuiCol.Text),
- ime.inputModeIcon);
+ if (stateFg >= 0x1000000)
+ {
+ imeIconFont.RenderChar(
+ drawList,
+ imeIconFont.FontSize,
+ cursor,
+ stateFg,
+ ime.inputModeIcon);
+ }
+
cursor.Y += candTextSize.Y + spaceY;
}
@@ -851,28 +867,34 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
if (expandUpward && drawIme)
{
- for (var dx = -2; dx <= 2; dx++)
+ if (stateBg >= 0x1000000)
{
- for (var dy = -2; dy <= 2; dy++)
+ for (var dx = -2; dx <= 2; dx++)
{
- if (dx != 0 || dy != 0)
+ for (var dy = -2; dy <= 2; dy++)
{
- imeIconFont.RenderChar(
- drawList,
- imeIconFont.FontSize,
- cursor + new Vector2(dx, dy),
- ImGui.GetColorU32(ImGuiCol.WindowBg),
- ime.inputModeIcon);
+ if (dx != 0 || dy != 0)
+ {
+ imeIconFont.RenderChar(
+ drawList,
+ imeIconFont.FontSize,
+ cursor + new Vector2(dx, dy),
+ ImGui.GetColorU32(ImGuiCol.WindowBg),
+ ime.inputModeIcon);
+ }
}
}
}
- imeIconFont.RenderChar(
- drawList,
- imeIconFont.FontSize,
- cursor,
- ImGui.GetColorU32(ImGuiCol.Text),
- ime.inputModeIcon);
+ if (stateFg >= 0x1000000)
+ {
+ imeIconFont.RenderChar(
+ drawList,
+ imeIconFont.FontSize,
+ cursor,
+ ImGui.GetColorU32(ImGuiCol.Text),
+ ime.inputModeIcon);
+ }
}
return;
diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs
index 04a05bd76..a582761ba 100644
--- a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs
+++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs
@@ -6,6 +6,7 @@ using System.Text;
using CheapLoc;
using Dalamud.Configuration.Internal;
using Dalamud.Game;
+using Dalamud.Game.Text;
using Dalamud.Interface.Colors;
using Dalamud.Interface.FontIdentifier;
using Dalamud.Interface.GameFonts;
@@ -136,6 +137,27 @@ public class SettingsTabLook : SettingsTab
Loc.Localize("DalamudSettingReducedMotionHint", "This will suppress certain animations from Dalamud, such as the notification popup."),
c => c.ReduceMotions ?? false,
(v, c) => c.ReduceMotions = v),
+
+ new SettingsEntry(
+ Loc.Localize("DalamudSettingImeStateIndicatorOpacity", "IME State Indicator Opacity (CJK only)"),
+ Loc.Localize("DalamudSettingImeStateIndicatorOpacityHint", "When any of CJK IMEs is in use, the state of IME will be shown with the opacity specified here."),
+ c => c.ImeStateIndicatorOpacity,
+ (v, c) => c.ImeStateIndicatorOpacity = v)
+ {
+ CustomDraw = static e =>
+ {
+ ImGuiHelpers.SafeTextWrapped(e.Name!);
+
+ var v = e.Value * 100f;
+ if (ImGui.SliderFloat($"###{e}", ref v, 0f, 100f, "%.1f%%"))
+ e.Value = v / 100f;
+ ImGui.SameLine();
+
+ ImGui.PushStyleVar(ImGuiStyleVar.Alpha, v / 100);
+ ImGui.TextUnformatted("\uE020\uE021\uE022\uE023\uE024\uE025\uE026\uE027");
+ ImGui.PopStyleVar(1);
+ },
+ },
};
public override string Title => Loc.Localize("DalamudSettingsVisual", "Look & Feel");
diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/SettingsEntry{T}.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/SettingsEntry{T}.cs
index f2a8dc46f..2ac4187cf 100644
--- a/Dalamud/Interface/Internal/Windows/Settings/Widgets/SettingsEntry{T}.cs
+++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/SettingsEntry{T}.cs
@@ -2,6 +2,7 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
+using System.Numerics;
using Dalamud.Configuration.Internal;
@@ -50,10 +51,22 @@ internal sealed class SettingsEntry : SettingsEntry
public delegate void SaveSettingDelegate(T? value, DalamudConfiguration config);
- public T? Value => this.valueBacking == default ? default : (T)this.valueBacking;
+ public T? Value
+ {
+ get => this.valueBacking == default ? default : (T)this.valueBacking;
+ set
+ {
+ if (Equals(value, this.valueBacking))
+ return;
+ this.valueBacking = value;
+ this.change?.Invoke(value);
+ }
+ }
public string Description { get; }
+ public Action>? CustomDraw { get; init; }
+
public Func? CheckValidity { get; init; }
public Func? CheckWarning { get; init; }
@@ -68,7 +81,11 @@ internal sealed class SettingsEntry : SettingsEntry
var type = typeof(T);
- if (type == typeof(DirectoryInfo))
+ if (this.CustomDraw is not null)
+ {
+ this.CustomDraw.Invoke(this);
+ }
+ else if (type == typeof(DirectoryInfo))
{
ImGuiHelpers.SafeTextWrapped(this.Name);
From d5d9942d91ee3e8bdc7710c88c866026e8466658 Mon Sep 17 00:00:00 2001
From: goat <16760685+goaaats@users.noreply.github.com>
Date: Sun, 26 May 2024 15:33:08 +0200
Subject: [PATCH 09/13] unfuck std::format (#1815)
---
Dalamud.Boot/logging.h | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/Dalamud.Boot/logging.h b/Dalamud.Boot/logging.h
index eff112a1b..1428ec7ff 100644
--- a/Dalamud.Boot/logging.h
+++ b/Dalamud.Boot/logging.h
@@ -111,9 +111,17 @@ namespace logging {
* @param arg1 First format parameter.
* @param args Second and further format parameters, if any.
*/
- template
- void print(Level level, const char* fmt, Arg&& arg1, Args&&...args) {
- print(level, std::vformat(fmt, std::make_format_args(to_format_arg(std::forward(arg1)), to_format_arg(std::forward(args))...)));
+ template
+ void print(Level level, const char* fmt, Arg&& arg1, Args&&... args) {
+ // make_format_args only accepts references now due to https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2905r2.html
+ // we can switch std::runtime_format in C++26 :) https://isocpp.org/files/papers/P2918R0.html
+ auto transformed_args = std::make_tuple(to_format_arg(arg1), to_format_arg(args)...);
+ auto format_args = std::apply(
+ [&](auto&... elems) { return std::make_format_args(elems...); },
+ transformed_args
+ );
+
+ print(level, std::vformat(fmt, format_args));
}
template void V(Args&&...args) { print(Level::Verbose, std::forward(args)...); }
From 9fcb890d20aace92b70257e9020951740d1bf214 Mon Sep 17 00:00:00 2001
From: Infi
Date: Mon, 27 May 2024 07:34:32 +0200
Subject: [PATCH 10/13] AutoTranslatePayload: Use `Alias` for TextCommands
(#1809)
---
.../SeStringHandling/Payloads/AutoTranslatePayload.cs | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/AutoTranslatePayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/AutoTranslatePayload.cs
index 451d43065..0315c0d6b 100644
--- a/Dalamud/Game/Text/SeStringHandling/Payloads/AutoTranslatePayload.cs
+++ b/Dalamud/Game/Text/SeStringHandling/Payloads/AutoTranslatePayload.cs
@@ -150,7 +150,7 @@ public class AutoTranslatePayload : Payload, ITextProvider
"PetMirage" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
"PlaceName" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
"Race" => this.DataResolver.GetExcelSheet().GetRow(this.key).Masculine,
- "TextCommand" => this.DataResolver.GetExcelSheet().GetRow(this.key).Command,
+ "TextCommand" => this.ResolveTextCommand(),
"Tribe" => this.DataResolver.GetExcelSheet().GetRow(this.key).Masculine,
"Weather" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
_ => throw new Exception(actualTableName),
@@ -166,4 +166,12 @@ public class AutoTranslatePayload : Payload, ITextProvider
return value;
}
+
+ private Lumina.Text.SeString ResolveTextCommand()
+ {
+ // TextCommands prioritize the `Alias` field, if it not empty
+ // Example for this is /rangerpose2l which becomes /blackrangerposeb in chat
+ var result = this.DataResolver.GetExcelSheet().GetRow(this.key);
+ return result.Alias.Payloads.Count > 0 ? result.Alias : result.Command;
+ }
}
From 10b44ba6d0d66059cc17a874df07669eb9c4c4c6 Mon Sep 17 00:00:00 2001
From: Infi
Date: Mon, 27 May 2024 07:51:45 +0200
Subject: [PATCH 11/13] AutoTranslatePayload: Add public property for group and
key (#1814)
---
.../Payloads/AutoTranslatePayload.cs | 66 +++++++++----------
1 file changed, 33 insertions(+), 33 deletions(-)
diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/AutoTranslatePayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/AutoTranslatePayload.cs
index 0315c0d6b..5c87ad43b 100644
--- a/Dalamud/Game/Text/SeStringHandling/Payloads/AutoTranslatePayload.cs
+++ b/Dalamud/Game/Text/SeStringHandling/Payloads/AutoTranslatePayload.cs
@@ -15,11 +15,11 @@ public class AutoTranslatePayload : Payload, ITextProvider
{
private string text;
- [JsonProperty]
- private uint group;
+ [JsonProperty("group")]
+ public uint Group { get; private set; }
- [JsonProperty]
- private uint key;
+ [JsonProperty("key")]
+ public uint Key { get; private set; }
///
/// Initializes a new instance of the class.
@@ -34,8 +34,8 @@ public class AutoTranslatePayload : Payload, ITextProvider
public AutoTranslatePayload(uint group, uint key)
{
// TODO: friendlier ctor? not sure how to handle that given how weird the tables are
- this.group = group;
- this.key = key;
+ this.Group = group;
+ this.Key = key;
}
///
@@ -69,20 +69,20 @@ public class AutoTranslatePayload : Payload, ITextProvider
/// A string that represents the current object.
public override string ToString()
{
- return $"{this.Type} - Group: {this.group}, Key: {this.key}, Text: {this.Text}";
+ return $"{this.Type} - Group: {this.Group}, Key: {this.Key}, Text: {this.Text}";
}
///
protected override byte[] EncodeImpl()
{
- var keyBytes = MakeInteger(this.key);
+ var keyBytes = MakeInteger(this.Key);
var chunkLen = keyBytes.Length + 2;
var bytes = new List()
{
START_BYTE,
(byte)SeStringChunkType.AutoTranslateKey, (byte)chunkLen,
- (byte)this.group,
+ (byte)this.Group,
};
bytes.AddRange(keyBytes);
bytes.Add(END_BYTE);
@@ -95,9 +95,9 @@ public class AutoTranslatePayload : Payload, ITextProvider
{
// this seems to always be a bare byte, and not following normal integer encoding
// the values in the table are all <70 so this is presumably ok
- this.group = reader.ReadByte();
+ this.Group = reader.ReadByte();
- this.key = GetInteger(reader);
+ this.Key = GetInteger(reader);
}
private string Resolve()
@@ -112,13 +112,13 @@ public class AutoTranslatePayload : Payload, ITextProvider
// try to get the row in the Completion table itself, because this is 'easiest'
// The row may not exist at all (if the Key is for another table), or it could be the wrong row
// (again, if it's meant for another table)
- row = sheet.GetRow(this.key);
+ row = sheet.GetRow(this.Key);
}
catch
{
} // don't care, row will be null
- if (row?.Group == this.group)
+ if (row?.Group == this.Group)
{
// if the row exists in this table and the group matches, this is actually the correct data
value = row.Text;
@@ -129,30 +129,30 @@ public class AutoTranslatePayload : Payload, ITextProvider
{
// we need to get the linked table and do the lookup there instead
// in this case, there will only be one entry for this group id
- row = sheet.First(r => r.Group == this.group);
+ row = sheet.First(r => r.Group == this.Group);
// many of the names contain valid id ranges after the table name, but we don't need those
var actualTableName = row.LookupTable.RawString.Split('[')[0];
var name = actualTableName switch
{
- "Action" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
- "ActionComboRoute" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
- "BuddyAction" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
- "ClassJob" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
- "Companion" => this.DataResolver.GetExcelSheet().GetRow(this.key).Singular,
- "CraftAction" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
- "GeneralAction" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
- "GuardianDeity" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
- "MainCommand" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
- "Mount" => this.DataResolver.GetExcelSheet().GetRow(this.key).Singular,
- "Pet" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
- "PetAction" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
- "PetMirage" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
- "PlaceName" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
- "Race" => this.DataResolver.GetExcelSheet().GetRow(this.key).Masculine,
+ "Action" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name,
+ "ActionComboRoute" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name,
+ "BuddyAction" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name,
+ "ClassJob" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name,
+ "Companion" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Singular,
+ "CraftAction" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name,
+ "GeneralAction" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name,
+ "GuardianDeity" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name,
+ "MainCommand" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name,
+ "Mount" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Singular,
+ "Pet" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name,
+ "PetAction" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name,
+ "PetMirage" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name,
+ "PlaceName" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name,
+ "Race" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Masculine,
"TextCommand" => this.ResolveTextCommand(),
- "Tribe" => this.DataResolver.GetExcelSheet().GetRow(this.key).Masculine,
- "Weather" => this.DataResolver.GetExcelSheet().GetRow(this.key).Name,
+ "Tribe" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Masculine,
+ "Weather" => this.DataResolver.GetExcelSheet().GetRow(this.Key).Name,
_ => throw new Exception(actualTableName),
};
@@ -160,7 +160,7 @@ public class AutoTranslatePayload : Payload, ITextProvider
}
catch (Exception e)
{
- Log.Error(e, $"AutoTranslatePayload - failed to resolve: {this.Type} - Group: {this.group}, Key: {this.key}");
+ Log.Error(e, $"AutoTranslatePayload - failed to resolve: {this.Type} - Group: {this.Group}, Key: {this.Key}");
}
}
@@ -171,7 +171,7 @@ public class AutoTranslatePayload : Payload, ITextProvider
{
// TextCommands prioritize the `Alias` field, if it not empty
// Example for this is /rangerpose2l which becomes /blackrangerposeb in chat
- var result = this.DataResolver.GetExcelSheet().GetRow(this.key);
+ var result = this.DataResolver.GetExcelSheet().GetRow(this.Key);
return result.Alias.Payloads.Count > 0 ? result.Alias : result.Command;
}
}
From b5d52732e0add94bf70c89fb20f9c355f36dfb0e Mon Sep 17 00:00:00 2001
From: MidoriKami <9083275+MidoriKami@users.noreply.github.com>
Date: Sat, 1 Jun 2024 15:04:06 -0700
Subject: [PATCH 12/13] Add hooking overloads (#1820)
---
.../GameInteropProviderPluginScoped.cs | 12 ++++++--
.../Plugin/Services/IGameInteropProvider.cs | 28 +++++++++++++++++--
2 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/Dalamud/Hooking/Internal/GameInteropProviderPluginScoped.cs b/Dalamud/Hooking/Internal/GameInteropProviderPluginScoped.cs
index 1138d4e07..eb096a771 100644
--- a/Dalamud/Hooking/Internal/GameInteropProviderPluginScoped.cs
+++ b/Dalamud/Hooking/Internal/GameInteropProviderPluginScoped.cs
@@ -47,7 +47,7 @@ internal class GameInteropProviderPluginScoped : IGameInteropProvider, IInternal
}
///
- public Hook HookFromFunctionPointerVariable(IntPtr address, T detour) where T : Delegate
+ public Hook HookFromFunctionPointerVariable(nint address, T detour) where T : Delegate
{
var hook = Hook.FromFunctionPointerVariable(address, detour);
this.trackedHooks.Add(hook);
@@ -71,13 +71,21 @@ internal class GameInteropProviderPluginScoped : IGameInteropProvider, IInternal
}
///
- public Hook HookFromAddress(IntPtr procAddress, T detour, IGameInteropProvider.HookBackend backend = IGameInteropProvider.HookBackend.Automatic) where T : Delegate
+ public Hook HookFromAddress(nint procAddress, T detour, IGameInteropProvider.HookBackend backend = IGameInteropProvider.HookBackend.Automatic) where T : Delegate
{
var hook = Hook.FromAddress(procAddress, detour, backend == IGameInteropProvider.HookBackend.MinHook);
this.trackedHooks.Add(hook);
return hook;
}
+ ///
+ public Hook HookFromAddress(UIntPtr procAddress, T detour, IGameInteropProvider.HookBackend backend = IGameInteropProvider.HookBackend.Automatic) where T : Delegate
+ => this.HookFromAddress((nint)procAddress, detour, backend);
+
+ ///
+ public unsafe Hook HookFromAddress(void* procAddress, T detour, IGameInteropProvider.HookBackend backend = IGameInteropProvider.HookBackend.Automatic) where T : Delegate
+ => this.HookFromAddress((nint)procAddress, detour, backend);
+
///
public Hook HookFromSignature(string signature, T detour, IGameInteropProvider.HookBackend backend = IGameInteropProvider.HookBackend.Automatic) where T : Delegate
=> this.HookFromAddress(this.scanner.ScanText(signature), detour, backend);
diff --git a/Dalamud/Plugin/Services/IGameInteropProvider.cs b/Dalamud/Plugin/Services/IGameInteropProvider.cs
index 217e08445..99e36c7ed 100644
--- a/Dalamud/Plugin/Services/IGameInteropProvider.cs
+++ b/Dalamud/Plugin/Services/IGameInteropProvider.cs
@@ -48,7 +48,7 @@ public interface IGameInteropProvider
/// Callback function. Delegate must have a same original function prototype.
/// The hook with the supplied parameters.
/// Delegate of detour.
- public Hook HookFromFunctionPointerVariable(IntPtr address, T detour) where T : Delegate;
+ public Hook HookFromFunctionPointerVariable(nint address, T detour) where T : Delegate;
///
/// Creates a hook by rewriting import table address.
@@ -85,7 +85,31 @@ public interface IGameInteropProvider
/// Hooking library to use.
/// The hook with the supplied parameters.
/// Delegate of detour.
- Hook HookFromAddress(IntPtr procAddress, T detour, HookBackend backend = HookBackend.Automatic) where T : Delegate;
+ Hook HookFromAddress(nint procAddress, T detour, HookBackend backend = HookBackend.Automatic) where T : Delegate;
+
+ ///
+ /// Creates a hook. Hooking address is inferred by calling to GetProcAddress() function.
+ /// The hook is not activated until Enable() method is called.
+ /// Please do not use MinHook unless you have thoroughly troubleshot why Reloaded does not work.
+ ///
+ /// A memory address to install a hook.
+ /// Callback function. Delegate must have a same original function prototype.
+ /// Hooking library to use.
+ /// The hook with the supplied parameters.
+ /// Delegate of detour.
+ Hook HookFromAddress(nuint procAddress, T detour, HookBackend backend = HookBackend.Automatic) where T : Delegate;
+
+ ///
+ /// Creates a hook. Hooking address is inferred by calling to GetProcAddress() function.
+ /// The hook is not activated until Enable() method is called.
+ /// Please do not use MinHook unless you have thoroughly troubleshot why Reloaded does not work.
+ ///
+ /// A memory address to install a hook.
+ /// Callback function. Delegate must have a same original function prototype.
+ /// Hooking library to use.
+ /// The hook with the supplied parameters.
+ /// Delegate of detour.
+ unsafe Hook HookFromAddress(void* procAddress, T detour, HookBackend backend = HookBackend.Automatic) where T : Delegate;
///
/// Creates a hook from a signature into the Dalamud target module.
From c21e525472af271e1796aeb868bcf39bae31a5a4 Mon Sep 17 00:00:00 2001
From: KazWolfe
Date: Sat, 1 Jun 2024 15:10:48 -0700
Subject: [PATCH 13/13] chore: Bump ClientStructs (#1816)
Bumps to c9cd1da plus custom changes, swaps target to goatcorp fork
of CS for 6.58_hf2 maintenance.
---
lib/FFXIVClientStructs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs
index 29dfda5cd..ce2d864cc 160000
--- a/lib/FFXIVClientStructs
+++ b/lib/FFXIVClientStructs
@@ -1 +1 @@
-Subproject commit 29dfda5cd439ce602e18630c22c2d1a5e2c094ec
+Subproject commit ce2d864cc91a6552740fdcd81f03992eedea6f95