From f7ef68d65e215afba1cf24cbfba9e0bb21e595c6 Mon Sep 17 00:00:00 2001
From: goat
Date: Tue, 17 Dec 2024 21:50:03 +0100
Subject: [PATCH 01/88] build: 11.0.3.0
---
Dalamud/Dalamud.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index 39bc83762..75afaae1b 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -9,7 +9,7 @@
- 11.0.2.0
+ 11.0.3.0
XIV Launcher addon framework
$(DalamudVersion)
$(DalamudVersion)
From 2e6cb6ef006da80a1d053d7693530444463d6d34 Mon Sep 17 00:00:00 2001
From: Infi
Date: Thu, 19 Dec 2024 22:19:50 +0100
Subject: [PATCH 02/88] - Add chat notification back to AutoUpdate (#2146)
- ImRaii UI elements in AutoUpdate tab
- Fix scoping in IconButton
---
.../Internal/DalamudConfiguration.cs | 19 ++-
.../Components/ImGuiComponents.IconButton.cs | 13 +-
.../DalamudComponents.PluginPicker.cs | 16 +-
.../Settings/Tabs/SettingsTabAutoUpdate.cs | 76 +++++----
.../Internal/AutoUpdate/AutoUpdateManager.cs | 156 ++++++++++++------
5 files changed, 166 insertions(+), 114 deletions(-)
diff --git a/Dalamud/Configuration/Internal/DalamudConfiguration.cs b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
index 5c2378f68..4df38d6df 100644
--- a/Dalamud/Configuration/Internal/DalamudConfiguration.cs
+++ b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
@@ -249,7 +249,7 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
/// Gets or sets a value indicating whether or not docking should be globally enabled in ImGui.
///
public bool IsDocking { get; set; }
-
+
///
/// Gets or sets a value indicating whether or not plugin user interfaces should trigger sound effects.
/// This setting is effected by the in-game "System Sounds" option and volume.
@@ -484,10 +484,15 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
public AutoUpdateBehavior? AutoUpdateBehavior { get; set; } = null;
///
- /// Gets or sets a value indicating whether or not users should be notified regularly about pending updates.
+ /// Gets or sets a value indicating whether users should be notified regularly about pending updates.
///
public bool CheckPeriodicallyForUpdates { get; set; } = true;
+ ///
+ /// Gets or sets a value indicating whether users should be notified about updates in chat.
+ ///
+ public bool SendUpdateNotificationToChat { get; set; } = false;
+
///
/// Load a configuration from the provided path.
///
@@ -504,7 +509,7 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
{
deserialized =
JsonConvert.DeserializeObject(text, SerializerSettings);
-
+
// If this reads as null, the file was empty, that's no good
if (deserialized == null)
throw new Exception("Read config was null.");
@@ -530,7 +535,7 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
{
Log.Error(e, "Failed to set defaults for DalamudConfiguration");
}
-
+
return deserialized;
}
@@ -549,7 +554,7 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
{
this.Save();
}
-
+
///
void IInternalDisposableService.DisposeService()
{
@@ -595,14 +600,14 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
this.ReduceMotions = winAnimEnabled == 0;
}
}
-
+
// Migrate old auto-update setting to new auto-update behavior
this.AutoUpdateBehavior ??= this.AutoUpdatePlugins
? Plugin.Internal.AutoUpdate.AutoUpdateBehavior.UpdateAll
: Plugin.Internal.AutoUpdate.AutoUpdateBehavior.OnlyNotify;
#pragma warning restore CS0618
}
-
+
private void Save()
{
ThreadSafety.AssertMainThread();
diff --git a/Dalamud/Interface/Components/ImGuiComponents.IconButton.cs b/Dalamud/Interface/Components/ImGuiComponents.IconButton.cs
index d2b1b4a36..10f177590 100644
--- a/Dalamud/Interface/Components/ImGuiComponents.IconButton.cs
+++ b/Dalamud/Interface/Components/ImGuiComponents.IconButton.cs
@@ -272,15 +272,14 @@ public static partial class ImGuiComponents
/// Width.
public static float GetIconButtonWithTextWidth(FontAwesomeIcon icon, string text)
{
+ Vector2 iconSize;
using (ImRaii.PushFont(UiBuilder.IconFont))
{
- var iconSize = ImGui.CalcTextSize(icon.ToIconString());
-
- var textSize = ImGui.CalcTextSize(text);
-
- var iconPadding = 3 * ImGuiHelpers.GlobalScale;
-
- return iconSize.X + textSize.X + (ImGui.GetStyle().FramePadding.X * 2) + iconPadding;
+ iconSize = ImGui.CalcTextSize(icon.ToIconString());
}
+
+ var textSize = ImGui.CalcTextSize(text);
+ var iconPadding = 3 * ImGuiHelpers.GlobalScale;
+ return iconSize.X + textSize.X + (ImGui.GetStyle().FramePadding.X * 2) + iconPadding;
}
}
diff --git a/Dalamud/Interface/Internal/DesignSystem/DalamudComponents.PluginPicker.cs b/Dalamud/Interface/Internal/DesignSystem/DalamudComponents.PluginPicker.cs
index f0ce6bc82..3d31bbda6 100644
--- a/Dalamud/Interface/Internal/DesignSystem/DalamudComponents.PluginPicker.cs
+++ b/Dalamud/Interface/Internal/DesignSystem/DalamudComponents.PluginPicker.cs
@@ -32,19 +32,21 @@ internal static partial class DalamudComponents
var pm = Service.GetNullable();
if (pm == null)
return 0;
-
+
var addPluginToProfilePopupId = ImGui.GetID(id);
using var popup = ImRaii.Popup(id);
if (popup.Success)
{
var width = ImGuiHelpers.GlobalScale * 300;
-
+
ImGui.SetNextItemWidth(width);
ImGui.InputTextWithHint("###pluginPickerSearch", Locs.SearchHint, ref pickerSearch, 255);
var currentSearchString = pickerSearch;
- if (ImGui.BeginListBox("###pluginPicker", new Vector2(width, width - 80)))
+
+ using var listBox = ImRaii.ListBox("###pluginPicker", new Vector2(width, width - 80));
+ if (listBox.Success)
{
// TODO: Plugin searching should be abstracted... installer and this should use the same search
var plugins = pm.InstalledPlugins.Where(
@@ -53,19 +55,15 @@ internal static partial class DalamudComponents
currentSearchString,
StringComparison.InvariantCultureIgnoreCase)))
.Where(pluginFiltered ?? (_ => true));
-
+
foreach (var plugin in plugins)
{
- using var disabled2 =
- ImRaii.Disabled(pluginDisabled(plugin));
-
+ using var disabled2 = ImRaii.Disabled(pluginDisabled(plugin));
if (ImGui.Selectable($"{plugin.Manifest.Name}{(plugin is LocalDevPlugin ? "(dev plugin)" : string.Empty)}###selector{plugin.Manifest.InternalName}"))
{
onClicked(plugin);
}
}
-
- ImGui.EndListBox();
}
}
diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAutoUpdate.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAutoUpdate.cs
index 77c79c96d..9356131ad 100644
--- a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAutoUpdate.cs
+++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAutoUpdate.cs
@@ -23,10 +23,11 @@ public class SettingsTabAutoUpdates : SettingsTab
{
private AutoUpdateBehavior behavior;
private bool checkPeriodically;
+ private bool chatNotification;
private string pickerSearch = string.Empty;
private List autoUpdatePreferences = [];
-
- public override SettingsEntry[] Entries { get; } = Array.Empty();
+
+ public override SettingsEntry[] Entries { get; } = [];
public override string Title => Loc.Localize("DalamudSettingsAutoUpdates", "Auto-Updates");
@@ -36,15 +37,15 @@ public class SettingsTabAutoUpdates : SettingsTab
"Dalamud can update your plugins automatically, making sure that you always " +
"have the newest features and bug fixes. You can choose when and how auto-updates are run here."));
ImGuiHelpers.ScaledDummy(2);
-
+
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsAutoUpdateDisclaimer1",
"You can always update your plugins manually by clicking the update button in the plugin list. " +
"You can also opt into updates for specific plugins by right-clicking them and selecting \"Always auto-update\"."));
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsAutoUpdateDisclaimer2",
"Dalamud will only notify you about updates while you are idle."));
-
+
ImGuiHelpers.ScaledDummy(8);
-
+
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudWhite, Loc.Localize("DalamudSettingsAutoUpdateBehavior",
"When the game starts..."));
var behaviorInt = (int)this.behavior;
@@ -62,20 +63,21 @@ public class SettingsTabAutoUpdates : SettingsTab
"These updates are not reviewed by the Dalamud team and may contain malicious code.");
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudOrange, warning);
}
-
+
ImGuiHelpers.ScaledDummy(8);
-
+
+ ImGui.Checkbox(Loc.Localize("DalamudSettingsAutoUpdateChatMessage", "Show notification about updates available in chat"), ref this.chatNotification);
ImGui.Checkbox(Loc.Localize("DalamudSettingsAutoUpdatePeriodically", "Periodically check for new updates while playing"), ref this.checkPeriodically);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsAutoUpdatePeriodicallyHint",
"Plugins won't update automatically after startup, you will only receive a notification while you are not actively playing."));
-
+
ImGuiHelpers.ScaledDummy(5);
ImGui.Separator();
ImGuiHelpers.ScaledDummy(5);
-
+
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudWhite, Loc.Localize("DalamudSettingsAutoUpdateOptedIn",
"Per-plugin overrides"));
-
+
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudWhite, Loc.Localize("DalamudSettingsAutoUpdateOverrideHint",
"Here, you can choose to receive or not to receive updates for specific plugins. " +
"This will override the settings above for the selected plugins."));
@@ -83,25 +85,25 @@ public class SettingsTabAutoUpdates : SettingsTab
if (this.autoUpdatePreferences.Count == 0)
{
ImGuiHelpers.ScaledDummy(20);
-
+
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudGrey))
{
ImGuiHelpers.CenteredText(Loc.Localize("DalamudSettingsAutoUpdateOptedInHint2",
"You don't have auto-update rules for any plugins."));
}
-
+
ImGuiHelpers.ScaledDummy(2);
}
else
{
ImGuiHelpers.ScaledDummy(5);
-
+
var pic = Service.Get();
var windowSize = ImGui.GetWindowSize();
var pluginLineHeight = 32 * ImGuiHelpers.GlobalScale;
Guid? wantRemovePluginGuid = null;
-
+
foreach (var preference in this.autoUpdatePreferences)
{
var pmPlugin = Service.Get().InstalledPlugins
@@ -120,11 +122,12 @@ public class SettingsTabAutoUpdates : SettingsTab
if (pmPlugin.IsDev)
{
ImGui.SetCursorPos(cursorBeforeIcon);
- ImGui.PushStyleVar(ImGuiStyleVar.Alpha, 0.7f);
- ImGui.Image(pic.DevPluginIcon.ImGuiHandle, new Vector2(pluginLineHeight));
- ImGui.PopStyleVar();
+ using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, 0.7f))
+ {
+ ImGui.Image(pic.DevPluginIcon.ImGuiHandle, new Vector2(pluginLineHeight));
+ }
}
-
+
ImGui.SameLine();
var text = $"{pmPlugin.Name}{(pmPlugin.IsDev ? " (dev plugin" : string.Empty)}";
@@ -147,7 +150,7 @@ public class SettingsTabAutoUpdates : SettingsTab
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (pluginLineHeight / 2) - (textHeight.Y / 2));
ImGui.TextUnformatted(text);
-
+
ImGui.SetCursorPos(before);
}
@@ -166,19 +169,18 @@ public class SettingsTabAutoUpdates : SettingsTab
}
ImGui.SetNextItemWidth(ImGuiHelpers.GlobalScale * 250);
- if (ImGui.BeginCombo(
- $"###autoUpdateBehavior{preference.WorkingPluginId}",
- OptKindToString(preference.Kind)))
+ using (var combo = ImRaii.Combo($"###autoUpdateBehavior{preference.WorkingPluginId}", OptKindToString(preference.Kind)))
{
- foreach (var kind in Enum.GetValues())
+ if (combo.Success)
{
- if (ImGui.Selectable(OptKindToString(kind)))
+ foreach (var kind in Enum.GetValues())
{
- preference.Kind = kind;
+ if (ImGui.Selectable(OptKindToString(kind)))
+ {
+ preference.Kind = kind;
+ }
}
}
-
- ImGui.EndCombo();
}
ImGui.SameLine();
@@ -193,7 +195,7 @@ public class SettingsTabAutoUpdates : SettingsTab
if (ImGui.IsItemHovered())
ImGui.SetTooltip(Loc.Localize("DalamudSettingsAutoUpdateOptInRemove", "Remove this override"));
}
-
+
if (wantRemovePluginGuid != null)
{
this.autoUpdatePreferences.RemoveAll(x => x.WorkingPluginId == wantRemovePluginGuid);
@@ -205,19 +207,19 @@ public class SettingsTabAutoUpdates : SettingsTab
var id = plugin.EffectiveWorkingPluginId;
if (id == Guid.Empty)
throw new InvalidOperationException("Plugin ID is empty.");
-
+
this.autoUpdatePreferences.Add(new AutoUpdatePreference(id));
}
-
+
bool IsPluginDisabled(LocalPlugin plugin)
=> this.autoUpdatePreferences.Any(x => x.WorkingPluginId == plugin.EffectiveWorkingPluginId);
-
+
bool IsPluginFiltered(LocalPlugin plugin)
=> !plugin.IsDev;
-
+
var pickerId = DalamudComponents.DrawPluginPicker(
"###autoUpdatePicker", ref this.pickerSearch, OnPluginPicked, IsPluginDisabled, IsPluginFiltered);
-
+
const FontAwesomeIcon addButtonIcon = FontAwesomeIcon.Plus;
var addButtonText = Loc.Localize("DalamudSettingsAutoUpdateOptInAdd", "Add new override");
ImGuiHelpers.CenterCursorFor(ImGuiComponents.GetIconButtonWithTextWidth(addButtonIcon, addButtonText));
@@ -235,20 +237,22 @@ public class SettingsTabAutoUpdates : SettingsTab
var configuration = Service.Get();
this.behavior = configuration.AutoUpdateBehavior ?? AutoUpdateBehavior.None;
+ this.chatNotification = configuration.SendUpdateNotificationToChat;
this.checkPeriodically = configuration.CheckPeriodicallyForUpdates;
this.autoUpdatePreferences = configuration.PluginAutoUpdatePreferences;
-
+
base.Load();
}
public override void Save()
{
var configuration = Service.Get();
-
+
configuration.AutoUpdateBehavior = this.behavior;
+ configuration.SendUpdateNotificationToChat = this.chatNotification;
configuration.CheckPeriodicallyForUpdates = this.checkPeriodically;
configuration.PluginAutoUpdatePreferences = this.autoUpdatePreferences;
-
+
base.Save();
}
}
diff --git a/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs b/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs
index c25ec4ee4..99850ddb4 100644
--- a/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs
+++ b/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs
@@ -9,6 +9,10 @@ using Dalamud.Console;
using Dalamud.Game;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Conditions;
+using Dalamud.Game.Gui;
+using Dalamud.Game.Text;
+using Dalamud.Game.Text.SeStringHandling;
+using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Interface;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.ImGuiNotification.EventArgs;
@@ -31,17 +35,17 @@ namespace Dalamud.Plugin.Internal.AutoUpdate;
internal class AutoUpdateManager : IServiceType
{
private static readonly ModuleLog Log = new("AUTOUPDATE");
-
+
///
/// Time we should wait after login to update.
///
private static readonly TimeSpan UpdateTimeAfterLogin = TimeSpan.FromSeconds(20);
-
+
///
/// Time we should wait between scheduled update checks.
///
private static readonly TimeSpan TimeBetweenUpdateChecks = TimeSpan.FromHours(2);
-
+
///
/// Time we should wait between scheduled update checks if the user has dismissed the notification,
/// instead of updating. We don't want to spam the user with notifications.
@@ -56,28 +60,30 @@ internal class AutoUpdateManager : IServiceType
[ServiceManager.ServiceDependency]
private readonly PluginManager pluginManager = Service.Get();
-
+
[ServiceManager.ServiceDependency]
private readonly DalamudConfiguration config = Service.Get();
-
+
[ServiceManager.ServiceDependency]
private readonly NotificationManager notificationManager = Service.Get();
-
+
[ServiceManager.ServiceDependency]
private readonly DalamudInterface dalamudInterface = Service.Get();
-
+
private readonly IConsoleVariable isDryRun;
-
+
private DateTime? loginTime;
private DateTime? nextUpdateCheckTime;
private DateTime? unblockedSince;
-
+
private bool hasStartedInitialUpdateThisSession;
private IActiveNotification? updateNotification;
-
+
private Task? autoUpdateTask;
-
+
+ private readonly Task openInstallerWindowLink;
+
///
/// Initializes a new instance of the class.
///
@@ -92,7 +98,18 @@ internal class AutoUpdateManager : IServiceType
t.Result.Logout += (int type, int code) => this.OnLogout();
});
Service.GetAsync().ContinueWith(t => { t.Result.Update += this.OnUpdate; });
-
+
+ this.openInstallerWindowLink =
+ Service.GetAsync().ContinueWith(
+ chatGuiTask => chatGuiTask.Result.AddChatLinkHandler(
+ "Dalamud",
+ 1001,
+ (_, _) =>
+ {
+ Service.GetNullable()?.OpenPluginInstallerTo(PluginInstallerOpenKind.InstalledPlugins);
+ }));
+
+
this.isDryRun = console.AddVariable("dalamud.autoupdate.dry_run", "Simulate updates instead", false);
console.AddCommand("dalamud.autoupdate.trigger_login", "Trigger a login event", () =>
{
@@ -106,36 +123,36 @@ internal class AutoUpdateManager : IServiceType
return true;
});
}
-
+
private enum UpdateListingRestriction
{
Unrestricted,
AllowNone,
AllowMainRepo,
}
-
+
///
/// Gets a value indicating whether or not auto-updates have already completed this session.
///
public bool IsAutoUpdateComplete { get; private set; }
-
+
///
/// Gets the time of the next scheduled update check.
///
public DateTime? NextUpdateCheckTime => this.nextUpdateCheckTime;
-
+
///
/// Gets the time the auto-update was unblocked.
///
public DateTime? UnblockedSince => this.unblockedSince;
-
+
private static UpdateListingRestriction DecideUpdateListingRestriction(AutoUpdateBehavior behavior)
{
return behavior switch
{
// We don't generally allow any updates in this mode, but specific opt-ins.
AutoUpdateBehavior.None => UpdateListingRestriction.AllowNone,
-
+
// If we're only notifying, I guess it's fine to list all plugins.
AutoUpdateBehavior.OnlyNotify => UpdateListingRestriction.Unrestricted,
@@ -144,7 +161,7 @@ internal class AutoUpdateManager : IServiceType
_ => throw new ArgumentOutOfRangeException(nameof(behavior), behavior, null),
};
}
-
+
private static void DrawOpenInstallerNotificationButton(bool primary, PluginInstallerOpenKind kind, IActiveNotification notification)
{
if (primary ?
@@ -179,7 +196,7 @@ internal class AutoUpdateManager : IServiceType
this.updateNotification = null;
}
}
-
+
// If we're blocked, we don't do anything.
if (!isUnblocked)
return;
@@ -199,16 +216,16 @@ internal class AutoUpdateManager : IServiceType
if (!this.hasStartedInitialUpdateThisSession && DateTime.Now > this.loginTime.Value.Add(UpdateTimeAfterLogin))
{
this.hasStartedInitialUpdateThisSession = true;
-
+
var currentlyUpdatablePlugins = this.GetAvailablePluginUpdates(DecideUpdateListingRestriction(behavior));
if (currentlyUpdatablePlugins.Count == 0)
{
this.IsAutoUpdateComplete = true;
this.nextUpdateCheckTime = DateTime.Now + TimeBetweenUpdateChecks;
-
+
return;
}
-
+
// TODO: This is not 100% what we want... Plugins that are opted-in should be updated regardless of the behavior,
// and we should show a notification for the others afterwards.
if (behavior == AutoUpdateBehavior.OnlyNotify)
@@ -241,6 +258,7 @@ internal class AutoUpdateManager : IServiceType
Log.Error(t.Exception!, "Failed to reload plugin masters for auto-update");
}
+ Log.Verbose($"Available Updates: {string.Join(", ", this.pluginManager.UpdatablePlugins.Select(s => s.UpdateManifest.InternalName))}");
var updatable = this.GetAvailablePluginUpdates(
DecideUpdateListingRestriction(behavior));
@@ -252,7 +270,7 @@ internal class AutoUpdateManager : IServiceType
{
this.nextUpdateCheckTime = DateTime.Now + TimeBetweenUpdateChecks;
Log.Verbose(
- "Auto update found nothing to do, next update at {Time}",
+ "Auto update found nothing to do, next update at {Time}",
this.nextUpdateCheckTime);
}
});
@@ -263,13 +281,13 @@ internal class AutoUpdateManager : IServiceType
{
if (this.updateNotification != null)
throw new InvalidOperationException("Already showing a notification");
-
+
this.updateNotification = this.notificationManager.AddNotification(notification);
this.updateNotification.Dismiss += _ =>
{
this.updateNotification = null;
-
+
// Schedule the next update opportunistically for when this closes.
this.nextUpdateCheckTime = DateTime.Now + TimeBetweenUpdateChecks;
};
@@ -291,7 +309,7 @@ internal class AutoUpdateManager : IServiceType
{
Log.Warning("Auto-update task was canceled");
}
-
+
this.autoUpdateTask = null;
this.IsAutoUpdateComplete = true;
});
@@ -321,20 +339,20 @@ internal class AutoUpdateManager : IServiceType
notification.Content = Locs.NotificationContentUpdating(updateProgress.CurrentPluginManifest.Name);
notification.Progress = (float)updateProgress.PluginsProcessed / updateProgress.TotalPlugins;
};
-
+
var pluginStates = (await this.pluginManager.UpdatePluginsAsync(updatablePlugins, this.isDryRun.Value, true, progress)).ToList();
this.pluginManager.PrintUpdatedPlugins(pluginStates, Loc.Localize("DalamudPluginAutoUpdate", "The following plugins were auto-updated:"));
notification.Progress = 1;
notification.UserDismissable = true;
notification.HardExpiry = DateTime.Now.AddSeconds(30);
-
+
notification.DrawActions += _ =>
{
ImGuiHelpers.ScaledDummy(2);
DrawOpenInstallerNotificationButton(true, PluginInstallerOpenKind.InstalledPlugins, notification);
};
-
+
// Update the notification to show the final state
if (pluginStates.All(x => x.Status == PluginUpdateStatus.StatusKind.Success))
{
@@ -342,7 +360,7 @@ internal class AutoUpdateManager : IServiceType
// Janky way to make sure the notification does not change before it's minimized...
await Task.Delay(500);
-
+
notification.Title = Locs.NotificationTitleUpdatesSuccessful;
notification.MinimizedText = Locs.NotificationContentUpdatesSuccessfulMinimized;
notification.Type = NotificationType.Success;
@@ -354,11 +372,11 @@ internal class AutoUpdateManager : IServiceType
notification.MinimizedText = Locs.NotificationContentUpdatesFailedMinimized;
notification.Type = NotificationType.Error;
notification.Content = Locs.NotificationContentUpdatesFailed;
-
+
var failedPlugins = pluginStates
.Where(x => x.Status != PluginUpdateStatus.StatusKind.Success)
.Select(x => x.Name).ToList();
-
+
notification.Content += "\n" + Locs.NotificationContentFailedPlugins(failedPlugins);
}
}
@@ -367,7 +385,7 @@ internal class AutoUpdateManager : IServiceType
{
if (updatablePlugins.Count == 0)
return;
-
+
var notification = this.GetBaseNotification(new Notification
{
Title = Locs.NotificationTitleUpdatesAvailable,
@@ -400,16 +418,44 @@ internal class AutoUpdateManager : IServiceType
notification.Dismiss += args =>
{
if (args.Reason != NotificationDismissReason.Manual) return;
-
+
this.nextUpdateCheckTime = DateTime.Now + TimeBetweenUpdateChecksIfDismissed;
Log.Verbose("User dismissed update notification, next check at {Time}", this.nextUpdateCheckTime);
};
+
+ // Send out a chat message only if the user requested so
+ if (!this.config.SendUpdateNotificationToChat)
+ return;
+
+ var chatGui = Service.GetNullable();
+ if (chatGui == null)
+ {
+ Log.Verbose("Unable to get chat gui, discard notification for chat.");
+ return;
+ }
+
+ chatGui.Print(new XivChatEntry
+ {
+ Message = new SeString(new List
+ {
+ new TextPayload(Locs.NotificationContentUpdatesAvailableMinimized(updatablePlugins.Count)),
+ new TextPayload(" ["),
+ new UIForegroundPayload(500),
+ this.openInstallerWindowLink.Result,
+ new TextPayload(Loc.Localize("DalamudInstallerHelp", "Open the plugin installer")),
+ RawPayload.LinkTerminator,
+ new UIForegroundPayload(0),
+ new TextPayload("]"),
+ }),
+
+ Type = XivChatType.Urgent,
+ });
}
-
+
private List GetAvailablePluginUpdates(UpdateListingRestriction restriction)
{
var optIns = this.config.PluginAutoUpdatePreferences.ToArray();
-
+
// Get all of our updatable plugins and do some initial filtering that must apply to all plugins.
var updateablePlugins = this.pluginManager.UpdatablePlugins
.Where(
@@ -423,14 +469,14 @@ internal class AutoUpdateManager : IServiceType
bool FilterPlugin(AvailablePluginUpdate availablePluginUpdate)
{
var optIn = optIns.FirstOrDefault(x => x.WorkingPluginId == availablePluginUpdate.InstalledPlugin.EffectiveWorkingPluginId);
-
+
// If this is an opt-out, we don't update.
if (optIn is { Kind: AutoUpdatePreference.OptKind.NeverUpdate })
return false;
if (restriction == UpdateListingRestriction.AllowNone && optIn is not { Kind: AutoUpdatePreference.OptKind.AlwaysUpdate })
return false;
-
+
if (restriction == UpdateListingRestriction.AllowMainRepo && availablePluginUpdate.InstalledPlugin.IsThirdParty)
return false;
@@ -442,7 +488,7 @@ internal class AutoUpdateManager : IServiceType
{
this.loginTime = DateTime.Now;
}
-
+
private void OnLogout()
{
this.loginTime = null;
@@ -452,7 +498,7 @@ internal class AutoUpdateManager : IServiceType
{
var condition = Service.Get();
return this.IsPluginManagerReady() &&
- !this.dalamudInterface.IsPluginInstallerOpen &&
+ !this.dalamudInterface.IsPluginInstallerOpen &&
condition.OnlyAny(ConditionFlag.NormalConditions,
ConditionFlag.Jumping,
ConditionFlag.Mounted,
@@ -469,21 +515,21 @@ internal class AutoUpdateManager : IServiceType
public static string NotificationButtonOpenPluginInstaller => Loc.Localize("AutoUpdateOpenPluginInstaller", "Open installer");
public static string NotificationButtonUpdate => Loc.Localize("AutoUpdateUpdate", "Update");
-
+
public static string NotificationTitleUpdatesAvailable => Loc.Localize("AutoUpdateUpdatesAvailable", "Updates available!");
-
+
public static string NotificationTitleUpdatesSuccessful => Loc.Localize("AutoUpdateUpdatesSuccessful", "Updates successful!");
-
+
public static string NotificationTitleUpdatingPlugins => Loc.Localize("AutoUpdateUpdatingPlugins", "Updating plugins...");
-
+
public static string NotificationTitleUpdatesFailed => Loc.Localize("AutoUpdateUpdatesFailed", "Updates failed!");
-
+
public static string NotificationContentUpdatesSuccessful => Loc.Localize("AutoUpdateUpdatesSuccessfulContent", "All plugins have been updated successfully.");
-
+
public static string NotificationContentUpdatesSuccessfulMinimized => Loc.Localize("AutoUpdateUpdatesSuccessfulContentMinimized", "Plugins updated successfully.");
-
+
public static string NotificationContentUpdatesFailed => Loc.Localize("AutoUpdateUpdatesFailedContent", "Some plugins failed to update. Please check the plugin installer for more information.");
-
+
public static string NotificationContentUpdatesFailedMinimized => Loc.Localize("AutoUpdateUpdatesFailedContentMinimized", "Plugins failed to update.");
public static string NotificationContentUpdatesAvailable(ICollection updatablePlugins)
@@ -497,20 +543,20 @@ internal class AutoUpdateManager : IServiceType
"There are {0} plugins that can be updated:"),
updatablePlugins.Count))
+ "\n\n" + string.Join(", ", updatablePlugins.Select(x => x.InstalledPlugin.Manifest.Name));
-
+
public static string NotificationContentUpdatesAvailableMinimized(int numUpdates)
=> numUpdates == 1 ?
- Loc.Localize("AutoUpdateUpdatesAvailableContentMinimizedSingular", "1 plugin update available") :
+ Loc.Localize("AutoUpdateUpdatesAvailableContentMinimizedSingular", "1 plugin update available") :
string.Format(Loc.Localize("AutoUpdateUpdatesAvailableContentMinimizedPlural", "{0} plugin updates available"), numUpdates);
-
+
public static string NotificationContentPreparingToUpdate(int numPlugins)
=> numPlugins == 1 ?
- Loc.Localize("AutoUpdatePreparingToUpdateSingular", "Preparing to update 1 plugin...") :
+ Loc.Localize("AutoUpdatePreparingToUpdateSingular", "Preparing to update 1 plugin...") :
string.Format(Loc.Localize("AutoUpdatePreparingToUpdatePlural", "Preparing to update {0} plugins..."), numPlugins);
-
+
public static string NotificationContentUpdating(string name)
=> string.Format(Loc.Localize("AutoUpdateUpdating", "Updating {0}..."), name);
-
+
public static string NotificationContentFailedPlugins(IEnumerable failedPlugins)
=> string.Format(Loc.Localize("AutoUpdateFailedPlugins", "Failed plugin(s): {0}"), string.Join(", ", failedPlugins));
}
From 87d069267bf848424530900add96f37dbab7c4d4 Mon Sep 17 00:00:00 2001
From: bleatbot <106497096+bleatbot@users.noreply.github.com>
Date: Fri, 20 Dec 2024 15:33:54 +0100
Subject: [PATCH 03/88] Update ClientStructs (#2148)
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 df03181cc..cc98a564d 160000
--- a/lib/FFXIVClientStructs
+++ b/lib/FFXIVClientStructs
@@ -1 +1 @@
-Subproject commit df03181ccbbbfead3db116b59359dae4a31cb07d
+Subproject commit cc98a564d0787813d4be082bf75f5bb98e0ed12f
From 2d6689b9d3d390abaaf9a9dd24d2a9eb4fdcd666 Mon Sep 17 00:00:00 2001
From: goat
Date: Sun, 22 Dec 2024 19:14:18 +0100
Subject: [PATCH 04/88] move lumina version out of csproj
---
Dalamud.CorePlugin/Dalamud.CorePlugin.csproj | 6 +++---
Dalamud/Dalamud.csproj | 8 ++++----
Directory.Build.props | 9 ++++++++-
3 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj b/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj
index b85607f0f..ca78f09ad 100644
--- a/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj
+++ b/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj
@@ -27,9 +27,9 @@
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index 75afaae1b..e1bb20db6 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -9,8 +9,8 @@
- 11.0.3.0
XIV Launcher addon framework
+ 11.0.3.0
$(DalamudVersion)
$(DalamudVersion)
$(DalamudVersion)
@@ -71,14 +71,14 @@
-
-
+
+
all
-
+
diff --git a/Directory.Build.props b/Directory.Build.props
index 0c5af2e37..6ee6f4b11 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,5 +1,12 @@
-
+
+
+ 5.6.0
+ 7.1.3
+ 13.0.3
+
+
+
From c647d07d94f7f6e2f192d22d3900f18e583df529 Mon Sep 17 00:00:00 2001
From: goat
Date: Sun, 22 Dec 2024 19:19:56 +0100
Subject: [PATCH 05/88] build: 11.0.4.0
---
Dalamud/Dalamud.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index e1bb20db6..a6ac07227 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -10,7 +10,7 @@
XIV Launcher addon framework
- 11.0.3.0
+ 11.0.4.0
$(DalamudVersion)
$(DalamudVersion)
$(DalamudVersion)
From bc21621d9ac1549a12e02854797be7a4234cd400 Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 23 Dec 2024 16:50:06 +0100
Subject: [PATCH 06/88] add release script
---
release.ps1 | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 release.ps1
diff --git a/release.ps1 b/release.ps1
new file mode 100644
index 000000000..8863a1214
--- /dev/null
+++ b/release.ps1
@@ -0,0 +1,31 @@
+param(
+ [string]$VersionString
+)
+
+if (-not $VersionString) {
+ Write-Error "Version string is required as the first argument."
+ exit 1
+}
+
+$csprojPath = "Dalamud/Dalamud.csproj"
+
+if (-not (Test-Path $csprojPath)) {
+ Write-Error "Cannot find Dalamud.csproj at the specified path."
+ exit 1
+}
+
+# Update the version in the csproj file
+(Get-Content $csprojPath) -replace '.*?', "$VersionString" | Set-Content $csprojPath
+
+# Commit the change
+git add $csprojPath
+git commit -m "build: $VersionString"
+
+# Get the current branch
+$currentBranch = git rev-parse --abbrev-ref HEAD
+
+# Create a tag
+git tag -a -m "v$VersionString" $VersionString
+
+# Push atomically
+git push origin $currentBranch $VersionString
\ No newline at end of file
From 8572ed8b1ef34c6fb0f961e7a073b6ed0d9c001b Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 23 Dec 2024 17:05:35 +0100
Subject: [PATCH 07/88] ProfileCommandHandler -> PluginManagementCommandHandler
---
.../Windows/PluginInstaller/ProfileManagerWidget.cs | 6 +++---
...eCommandHandler.cs => PluginManagementCommandHandler.cs} | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
rename Dalamud/Plugin/Internal/Profiles/{ProfileCommandHandler.cs => PluginManagementCommandHandler.cs} (95%)
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs
index 95315dbd3..ee93d2042 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs
@@ -625,13 +625,13 @@ internal class ProfileManagerWidget
Loc.Localize("ProfileManagerTutorialCommands", "You can use the following commands in chat or in macros to manage active collections:");
public static string TutorialCommandsEnable =>
- Loc.Localize("ProfileManagerTutorialCommandsEnable", "{0} \"Collection Name\" - Enable a collection").Format(ProfileCommandHandler.CommandEnable);
+ Loc.Localize("ProfileManagerTutorialCommandsEnable", "{0} \"Collection Name\" - Enable a collection").Format(PluginManagementCommandHandler.CommandEnable);
public static string TutorialCommandsDisable =>
- Loc.Localize("ProfileManagerTutorialCommandsDisable", "{0} \"Collection Name\" - Disable a collection").Format(ProfileCommandHandler.CommandDisable);
+ Loc.Localize("ProfileManagerTutorialCommandsDisable", "{0} \"Collection Name\" - Disable a collection").Format(PluginManagementCommandHandler.CommandDisable);
public static string TutorialCommandsToggle =>
- Loc.Localize("ProfileManagerTutorialCommandsToggle", "{0} \"Collection Name\" - Toggle a collection's state").Format(ProfileCommandHandler.CommandToggle);
+ Loc.Localize("ProfileManagerTutorialCommandsToggle", "{0} \"Collection Name\" - Toggle a collection's state").Format(PluginManagementCommandHandler.CommandToggle);
public static string TutorialCommandsEnd =>
Loc.Localize("ProfileManagerTutorialCommandsEnd", "If you run multiple of these commands, they will be executed in order.");
diff --git a/Dalamud/Plugin/Internal/Profiles/ProfileCommandHandler.cs b/Dalamud/Plugin/Internal/Profiles/PluginManagementCommandHandler.cs
similarity index 95%
rename from Dalamud/Plugin/Internal/Profiles/ProfileCommandHandler.cs
rename to Dalamud/Plugin/Internal/Profiles/PluginManagementCommandHandler.cs
index 7b7b4cfd0..d219b659b 100644
--- a/Dalamud/Plugin/Internal/Profiles/ProfileCommandHandler.cs
+++ b/Dalamud/Plugin/Internal/Profiles/PluginManagementCommandHandler.cs
@@ -16,7 +16,7 @@ namespace Dalamud.Plugin.Internal.Profiles;
/// Service responsible for profile-related chat commands.
///
[ServiceManager.EarlyLoadedService]
-internal class ProfileCommandHandler : IInternalDisposableService
+internal class PluginManagementCommandHandler : IInternalDisposableService
{
#pragma warning disable SA1600
public const string CommandEnable = "/xlenablecollection";
@@ -36,14 +36,14 @@ internal class ProfileCommandHandler : IInternalDisposableService
private List<(string, ProfileOp)> queue = new();
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// Command handler.
/// Profile manager.
/// Chat handler.
/// Framework.
[ServiceManager.ServiceConstructor]
- public ProfileCommandHandler(CommandManager cmd, ProfileManager profileManager, ChatGui chat, Framework framework)
+ public PluginManagementCommandHandler(CommandManager cmd, ProfileManager profileManager, ChatGui chat, Framework framework)
{
this.cmd = cmd;
this.profileManager = profileManager;
From 8276c19c6f016d58da414916074c4a5a764ad26e Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 23 Dec 2024 20:55:57 +0100
Subject: [PATCH 08/88] add plugin enable/disable/toggle commands
---
.../PluginInstaller/ProfileManagerWidget.cs | 6 +-
.../PluginManagementCommandHandler.cs | 318 ++++++++++++++----
2 files changed, 254 insertions(+), 70 deletions(-)
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs
index ee93d2042..ddb89d38c 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs
@@ -625,13 +625,13 @@ internal class ProfileManagerWidget
Loc.Localize("ProfileManagerTutorialCommands", "You can use the following commands in chat or in macros to manage active collections:");
public static string TutorialCommandsEnable =>
- Loc.Localize("ProfileManagerTutorialCommandsEnable", "{0} \"Collection Name\" - Enable a collection").Format(PluginManagementCommandHandler.CommandEnable);
+ Loc.Localize("ProfileManagerTutorialCommandsEnable", "{0} \"Collection Name\" - Enable a collection").Format(PluginManagementCommandHandler.CommandEnableProfile);
public static string TutorialCommandsDisable =>
- Loc.Localize("ProfileManagerTutorialCommandsDisable", "{0} \"Collection Name\" - Disable a collection").Format(PluginManagementCommandHandler.CommandDisable);
+ Loc.Localize("ProfileManagerTutorialCommandsDisable", "{0} \"Collection Name\" - Disable a collection").Format(PluginManagementCommandHandler.CommandDisableProfile);
public static string TutorialCommandsToggle =>
- Loc.Localize("ProfileManagerTutorialCommandsToggle", "{0} \"Collection Name\" - Toggle a collection's state").Format(PluginManagementCommandHandler.CommandToggle);
+ Loc.Localize("ProfileManagerTutorialCommandsToggle", "{0} \"Collection Name\" - Toggle a collection's state").Format(PluginManagementCommandHandler.CommandToggleProfile);
public static string TutorialCommandsEnd =>
Loc.Localize("ProfileManagerTutorialCommandsEnd", "If you run multiple of these commands, they will be executed in order.");
diff --git a/Dalamud/Plugin/Internal/Profiles/PluginManagementCommandHandler.cs b/Dalamud/Plugin/Internal/Profiles/PluginManagementCommandHandler.cs
index d219b659b..ad5aad286 100644
--- a/Dalamud/Plugin/Internal/Profiles/PluginManagementCommandHandler.cs
+++ b/Dalamud/Plugin/Internal/Profiles/PluginManagementCommandHandler.cs
@@ -6,6 +6,7 @@ using CheapLoc;
using Dalamud.Game;
using Dalamud.Game.Command;
using Dalamud.Game.Gui;
+using Dalamud.Plugin.Internal.Types;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
using Serilog;
@@ -19,50 +20,62 @@ namespace Dalamud.Plugin.Internal.Profiles;
internal class PluginManagementCommandHandler : IInternalDisposableService
{
#pragma warning disable SA1600
- public const string CommandEnable = "/xlenablecollection";
- public const string CommandDisable = "/xldisablecollection";
- public const string CommandToggle = "/xltogglecollection";
+ public const string CommandEnableProfile = "/xlenablecollection";
+ public const string CommandDisableProfile = "/xldisablecollection";
+ public const string CommandToggleProfile = "/xltogglecollection";
+
+ public const string CommandEnablePlugin = "/xlenableplugin";
+ public const string CommandDisablePlugin = "/xldisableplugin";
+ public const string CommandTogglePlugin = "/xltoggleplugin";
#pragma warning restore SA1600
- private static readonly string LegacyCommandEnable = CommandEnable.Replace("collection", "profile");
- private static readonly string LegacyCommandDisable = CommandDisable.Replace("collection", "profile");
- private static readonly string LegacyCommandToggle = CommandToggle.Replace("collection", "profile");
+ private static readonly string LegacyCommandEnable = CommandEnableProfile.Replace("collection", "profile");
+ private static readonly string LegacyCommandDisable = CommandDisableProfile.Replace("collection", "profile");
+ private static readonly string LegacyCommandToggle = CommandToggleProfile.Replace("collection", "profile");
private readonly CommandManager cmd;
private readonly ProfileManager profileManager;
+ private readonly PluginManager pluginManager;
private readonly ChatGui chat;
private readonly Framework framework;
- private List<(string, ProfileOp)> queue = new();
-
+ private List<(Target Target, PluginCommandOperation Operation)> commandQueue = new();
+
///
/// Initializes a new instance of the class.
///
/// Command handler.
/// Profile manager.
+ /// Plugin manager.
/// Chat handler.
/// Framework.
[ServiceManager.ServiceConstructor]
- public PluginManagementCommandHandler(CommandManager cmd, ProfileManager profileManager, ChatGui chat, Framework framework)
+ public PluginManagementCommandHandler(
+ CommandManager cmd,
+ ProfileManager profileManager,
+ PluginManager pluginManager,
+ ChatGui chat,
+ Framework framework)
{
this.cmd = cmd;
this.profileManager = profileManager;
+ this.pluginManager = pluginManager;
this.chat = chat;
this.framework = framework;
- this.cmd.AddHandler(CommandEnable, new CommandInfo(this.OnEnableProfile)
+ this.cmd.AddHandler(CommandEnableProfile, new CommandInfo(this.OnEnableProfile)
{
HelpMessage = Loc.Localize("ProfileCommandsEnableHint", "Enable a collection. Usage: /xlenablecollection \"Collection Name\""),
ShowInHelp = true,
});
- this.cmd.AddHandler(CommandDisable, new CommandInfo(this.OnDisableProfile)
+ this.cmd.AddHandler(CommandDisableProfile, new CommandInfo(this.OnDisableProfile)
{
HelpMessage = Loc.Localize("ProfileCommandsDisableHint", "Disable a collection. Usage: /xldisablecollection \"Collection Name\""),
ShowInHelp = true,
});
- this.cmd.AddHandler(CommandToggle, new CommandInfo(this.OnToggleProfile)
+ this.cmd.AddHandler(CommandToggleProfile, new CommandInfo(this.OnToggleProfile)
{
HelpMessage = Loc.Localize("ProfileCommandsToggleHint", "Toggle a collection. Usage: /xltogglecollection \"Collection Name\""),
ShowInHelp = true,
@@ -75,18 +88,36 @@ internal class PluginManagementCommandHandler : IInternalDisposableService
this.cmd.AddHandler(LegacyCommandDisable, new CommandInfo(this.OnDisableProfile)
{
- ShowInHelp = true,
+ ShowInHelp = false,
});
this.cmd.AddHandler(LegacyCommandToggle, new CommandInfo(this.OnToggleProfile)
{
+ ShowInHelp = false,
+ });
+
+ this.cmd.AddHandler(CommandEnablePlugin, new CommandInfo(this.OnEnablePlugin)
+ {
+ HelpMessage = Loc.Localize("PluginCommandsEnableHint", "Enable a plugin. Usage: /xlenableplugin \"Plugin Name\""),
+ ShowInHelp = true,
+ });
+
+ this.cmd.AddHandler(CommandDisablePlugin, new CommandInfo(this.OnDisablePlugin)
+ {
+ HelpMessage = Loc.Localize("PluginCommandsDisableHint", "Disable a plugin. Usage: /xldisableplugin \"Plugin Name\""),
+ ShowInHelp = true,
+ });
+
+ this.cmd.AddHandler(CommandTogglePlugin, new CommandInfo(this.OnTogglePlugin)
+ {
+ HelpMessage = Loc.Localize("PluginCommandsToggleHint", "Toggle a plugin. Usage: /xltoggleplugin \"Plugin Name\""),
ShowInHelp = true,
});
this.framework.Update += this.FrameworkOnUpdate;
}
- private enum ProfileOp
+ private enum PluginCommandOperation
{
Enable,
Disable,
@@ -96,109 +127,262 @@ internal class PluginManagementCommandHandler : IInternalDisposableService
///
void IInternalDisposableService.DisposeService()
{
- this.cmd.RemoveHandler(CommandEnable);
- this.cmd.RemoveHandler(CommandDisable);
- this.cmd.RemoveHandler(CommandToggle);
+ this.cmd.RemoveHandler(CommandEnableProfile);
+ this.cmd.RemoveHandler(CommandDisableProfile);
+ this.cmd.RemoveHandler(CommandToggleProfile);
this.cmd.RemoveHandler(LegacyCommandEnable);
this.cmd.RemoveHandler(LegacyCommandDisable);
this.cmd.RemoveHandler(LegacyCommandToggle);
this.framework.Update += this.FrameworkOnUpdate;
}
-
- private void FrameworkOnUpdate(IFramework framework1)
+
+ private void HandleProfileOperation(string profileName, PluginCommandOperation operation)
{
- if (this.profileManager.IsBusy)
+ var profile = this.profileManager.Profiles.FirstOrDefault(
+ x => x.Name == profileName);
+ if (profile == null || profile.IsDefaultProfile)
return;
- if (this.queue.Count > 0)
+ switch (operation)
{
- var op = this.queue[0];
- this.queue.RemoveAt(0);
+ case PluginCommandOperation.Enable:
+ if (!profile.IsEnabled)
+ Task.Run(() => profile.SetStateAsync(true, false)).GetAwaiter().GetResult();
+ break;
+ case PluginCommandOperation.Disable:
+ if (profile.IsEnabled)
+ Task.Run(() => profile.SetStateAsync(false, false)).GetAwaiter().GetResult();
+ break;
+ case PluginCommandOperation.Toggle:
+ Task.Run(() => profile.SetStateAsync(!profile.IsEnabled, false)).GetAwaiter().GetResult();
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(operation), operation, null);
+ }
- var profile = this.profileManager.Profiles.FirstOrDefault(x => x.Name == op.Item1);
- if (profile == null || profile.IsDefaultProfile)
- return;
+ this.chat.Print(
+ profile.IsEnabled
+ ? Loc.Localize("ProfileCommandsEnabling", "Enabling collection \"{0}\"...").Format(profile.Name)
+ : Loc.Localize("ProfileCommandsDisabling", "Disabling collection \"{0}\"...").Format(profile.Name));
- switch (op.Item2)
+ Task.Run(this.profileManager.ApplyAllWantStatesAsync).ContinueWith(t =>
+ {
+ if (!t.IsCompletedSuccessfully && t.Exception != null)
{
- case ProfileOp.Enable:
- if (!profile.IsEnabled)
- Task.Run(() => profile.SetStateAsync(true, false)).GetAwaiter().GetResult();
- break;
- case ProfileOp.Disable:
- if (profile.IsEnabled)
- Task.Run(() => profile.SetStateAsync(false, false)).GetAwaiter().GetResult();
- break;
- case ProfileOp.Toggle:
- Task.Run(() => profile.SetStateAsync(!profile.IsEnabled, false)).GetAwaiter().GetResult();
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
-
- if (profile.IsEnabled)
- {
- this.chat.Print(Loc.Localize("ProfileCommandsEnabling", "Enabling collection \"{0}\"...").Format(profile.Name));
+ Log.Error(t.Exception, "Could not apply profiles through commands");
+ this.chat.PrintError(Loc.Localize("ProfileCommandsApplyFailed", "Failed to apply your collections. Please check the console for errors."));
}
else
{
- this.chat.Print(Loc.Localize("ProfileCommandsDisabling", "Disabling collection \"{0}\"...").Format(profile.Name));
+ this.chat.Print(Loc.Localize("ProfileCommandsApplySuccess", "Collections applied."));
}
+ });
+ }
+
+ private bool HandlePluginOperation(Guid workingPluginId, PluginCommandOperation operation)
+ {
+ var plugin = this.pluginManager.InstalledPlugins.FirstOrDefault(x => x.EffectiveWorkingPluginId == workingPluginId);
+ if (plugin == null)
+ return true;
- Task.Run(this.profileManager.ApplyAllWantStatesAsync).ContinueWith(t =>
+ switch (plugin.State)
+ {
+ // Ignore if the plugin is in a fail state
+ case PluginState.LoadError or PluginState.UnloadError:
+ this.chat.Print(Loc.Localize("PluginCommandsFailed", "Plugin \"{0}\" has previously failed to load/unload, not continuing.").Format(plugin.Name));
+ return true;
+
+ case PluginState.Loaded when operation == PluginCommandOperation.Enable:
+ this.chat.Print(Loc.Localize("PluginCommandsAlreadyEnabled", "Plugin \"{0}\" is already enabled.").Format(plugin.Name));
+ return true;
+ case PluginState.Unloaded when operation == PluginCommandOperation.Disable:
+ this.chat.Print(Loc.Localize("PluginCommandsAlreadyDisabled", "Plugin \"{0}\" is already disabled.").Format(plugin.Name));
+ return true;
+
+ // Defer if this plugin is busy right now
+ case PluginState.Loading or PluginState.Unloading:
+ return false;
+ }
+
+ void Continuation(Task t, string onSuccess, string onError)
+ {
+ if (!t.IsCompletedSuccessfully && t.Exception != null)
{
- if (!t.IsCompletedSuccessfully && t.Exception != null)
- {
- Log.Error(t.Exception, "Could not apply profiles through commands");
- this.chat.PrintError(Loc.Localize("ProfileCommandsApplyFailed", "Failed to apply your collections. Please check the console for errors."));
- }
- else
- {
- this.chat.Print(Loc.Localize("ProfileCommandsApplySuccess", "Collections applied."));
- }
- });
+ Log.Error(t.Exception, "Plugin command operation failed for plugin {PluginName}", plugin.Name);
+ this.chat.PrintError(onError);
+ return;
+ }
+
+ this.chat.Print(onSuccess);
+ }
+
+ switch (operation)
+ {
+ case PluginCommandOperation.Enable:
+ this.chat.Print(Loc.Localize("PluginCommandsEnabling", "Enabling plugin \"{0}\"...").Format(plugin.Name));
+ Task.Run(() => plugin.LoadAsync(PluginLoadReason.Installer))
+ .ContinueWith(t => Continuation(t,
+ Loc.Localize("PluginCommandsEnableSuccess", "Plugin \"{0}\" enabled.").Format(plugin.Name),
+ Loc.Localize("PluginCommandsEnableFailed", "Failed to enable plugin \"{0}\". Please check the console for errors.").Format(plugin.Name)))
+ .ConfigureAwait(false);
+ break;
+ case PluginCommandOperation.Disable:
+ this.chat.Print(Loc.Localize("PluginCommandsDisabling", "Disabling plugin \"{0}\"...").Format(plugin.Name));
+ Task.Run(() => plugin.UnloadAsync())
+ .ContinueWith(t => Continuation(t,
+ Loc.Localize("PluginCommandsDisableSuccess", "Plugin \"{0}\" disabled.").Format(plugin.Name),
+ Loc.Localize("PluginCommandsDisableFailed", "Failed to disable plugin \"{0}\". Please check the console for errors.").Format(plugin.Name)))
+ .ConfigureAwait(false);
+ break;
+ case PluginCommandOperation.Toggle:
+ this.chat.Print(Loc.Localize("PluginCommandsToggling", "Toggling plugin \"{0}\"...").Format(plugin.Name));
+ Task.Run(() => plugin.State == PluginState.Loaded ? plugin.UnloadAsync() : plugin.LoadAsync(PluginLoadReason.Installer))
+ .ContinueWith(t => Continuation(t,
+ Loc.Localize("PluginCommandsToggleSuccess", "Plugin \"{0}\" toggled.").Format(plugin.Name),
+ Loc.Localize("PluginCommandsToggleFailed", "Failed to toggle plugin \"{0}\". Please check the console for errors.").Format(plugin.Name)))
+ .ConfigureAwait(false);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(operation), operation, null);
+ }
+
+ return true;
+ }
+
+ private void FrameworkOnUpdate(IFramework framework1)
+ {
+ if (this.profileManager.IsBusy)
+ {
+ return;
+ }
+
+ if (this.commandQueue.Count > 0)
+ {
+ var op = this.commandQueue[0];
+
+ var remove = true;
+ switch (op.Target)
+ {
+ case PluginTarget pluginTarget:
+ remove = this.HandlePluginOperation(pluginTarget.WorkingPluginId, op.Operation);
+ break;
+ case ProfileTarget profileTarget:
+ this.HandleProfileOperation(profileTarget.ProfileName, op.Operation);
+ break;
+ }
+
+ if (remove)
+ {
+ this.commandQueue.RemoveAt(0);
+ }
}
}
private void OnEnableProfile(string command, string arguments)
{
- var name = this.ValidateName(arguments);
+ var name = this.ValidateProfileName(arguments);
if (name == null)
return;
- this.queue = this.queue.Where(x => x.Item1 != name).ToList();
- this.queue.Add((name, ProfileOp.Enable));
+ var target = new ProfileTarget(name);
+ this.commandQueue = this.commandQueue.Where(x => x.Target != target).ToList();
+ this.commandQueue.Add((target, PluginCommandOperation.Enable));
}
private void OnDisableProfile(string command, string arguments)
{
- var name = this.ValidateName(arguments);
+ var name = this.ValidateProfileName(arguments);
if (name == null)
return;
- this.queue = this.queue.Where(x => x.Item1 != name).ToList();
- this.queue.Add((name, ProfileOp.Disable));
+ var target = new ProfileTarget(name);
+ this.commandQueue = this.commandQueue.Where(x => x.Target != target).ToList();
+ this.commandQueue.Add((target, PluginCommandOperation.Disable));
}
private void OnToggleProfile(string command, string arguments)
{
- var name = this.ValidateName(arguments);
+ var name = this.ValidateProfileName(arguments);
if (name == null)
return;
- this.queue.Add((name, ProfileOp.Toggle));
+ var target = new ProfileTarget(name);
+ this.commandQueue.Add((target, PluginCommandOperation.Toggle));
+ }
+
+ private void OnEnablePlugin(string command, string arguments)
+ {
+ var plugin = this.ValidatePluginName(arguments);
+ if (plugin == null)
+ return;
+
+ var target = new PluginTarget(plugin.EffectiveWorkingPluginId);
+ this.commandQueue
+ .RemoveAll(x => x.Target == target);
+ this.commandQueue.Add((target, PluginCommandOperation.Enable));
+ }
+
+ private void OnDisablePlugin(string command, string arguments)
+ {
+ var plugin = this.ValidatePluginName(arguments);
+ if (plugin == null)
+ return;
+
+ var target = new PluginTarget(plugin.EffectiveWorkingPluginId);
+ this.commandQueue
+ .RemoveAll(x => x.Target == target);
+ this.commandQueue.Add((target, PluginCommandOperation.Disable));
+ }
+
+ private void OnTogglePlugin(string command, string arguments)
+ {
+ var plugin = this.ValidatePluginName(arguments);
+ if (plugin == null)
+ return;
+
+ var target = new PluginTarget(plugin.EffectiveWorkingPluginId);
+ this.commandQueue
+ .RemoveAll(x => x.Target == target);
+ this.commandQueue.Add((target, PluginCommandOperation.Toggle));
}
- private string? ValidateName(string arguments)
+ private string? ValidateProfileName(string arguments)
{
var name = arguments.Replace("\"", string.Empty);
if (this.profileManager.Profiles.All(x => x.Name != name))
{
- this.chat.PrintError($"No collection like \"{name}\".");
+ this.chat.PrintError(Loc.Localize("ProfileCommandsNotFound", "Collection \"{0}\" not found.").Format(name));
return null;
}
return name;
}
+
+ private LocalPlugin? ValidatePluginName(string arguments)
+ {
+ var name = arguments.Replace("\"", string.Empty);
+ var targetPlugin =
+ this.pluginManager.InstalledPlugins.FirstOrDefault(x => x.InternalName == name || x.Name.Equals(name, StringComparison.CurrentCultureIgnoreCase));
+
+ if (targetPlugin == null)
+ {
+ this.chat.PrintError(Loc.Localize("PluginCommandsNotFound", "Plugin \"{0}\" not found.").Format(name));
+ return null;
+ }
+
+ if (!this.profileManager.IsInDefaultProfile(targetPlugin.EffectiveWorkingPluginId))
+ {
+ this.chat.PrintError(Loc.Localize("PluginCommandsNotInDefaultProfile", "Plugin \"{0}\" is in a collection and can't be managed through commands. Manage the collection instead.")
+ .Format(targetPlugin.Name));
+ }
+
+ return targetPlugin;
+ }
+
+ private abstract record Target;
+
+ private record PluginTarget(Guid WorkingPluginId) : Target;
+
+ private record ProfileTarget(string ProfileName) : Target;
}
From a1ae33bfee3f5a8f61c7617d59bdafa4279887ef Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 23 Dec 2024 21:03:31 +0100
Subject: [PATCH 09/88] don't set plugin to fail state if we threw
InvalidPluginOperationException These are supposed to indicate to the user
that they called a function at the wrong point in time. We don't want to
actually mutate the state in that case.
---
.../Exceptions/InternalPluginStateException.cs | 16 ++++++++++++++++
Dalamud/Plugin/Internal/Types/LocalPlugin.cs | 11 ++++++++---
2 files changed, 24 insertions(+), 3 deletions(-)
create mode 100644 Dalamud/Plugin/Internal/Exceptions/InternalPluginStateException.cs
diff --git a/Dalamud/Plugin/Internal/Exceptions/InternalPluginStateException.cs b/Dalamud/Plugin/Internal/Exceptions/InternalPluginStateException.cs
new file mode 100644
index 000000000..03e37afcf
--- /dev/null
+++ b/Dalamud/Plugin/Internal/Exceptions/InternalPluginStateException.cs
@@ -0,0 +1,16 @@
+namespace Dalamud.Plugin.Internal.Exceptions;
+
+///
+/// An exception to be thrown when policy blocks a plugin from loading.
+///
+internal class InternalPluginStateException : InvalidPluginOperationException
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The message to associate with this exception.
+ public InternalPluginStateException(string message)
+ : base(message)
+ {
+ }
+}
diff --git a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs
index 59f6b23c1..ed3a94994 100644
--- a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs
+++ b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs
@@ -281,7 +281,7 @@ internal class LocalPlugin : IAsyncDisposable
case PluginState.Unloaded:
if (this.instance is not null)
{
- throw new InvalidPluginOperationException(
+ throw new InternalPluginStateException(
"Plugin should have been unloaded but instance is not cleared");
}
@@ -413,7 +413,9 @@ internal class LocalPlugin : IAsyncDisposable
}
catch (Exception ex)
{
- this.State = PluginState.LoadError;
+ // These are "user errors", we don't want to mark the plugin as failed
+ if (ex is not InvalidPluginOperationException)
+ this.State = PluginState.LoadError;
// If a precondition fails, don't record it as an error, as it isn't really.
if (ex is PluginPreconditionFailedException)
@@ -476,7 +478,10 @@ internal class LocalPlugin : IAsyncDisposable
}
catch (Exception ex)
{
- this.State = PluginState.UnloadError;
+ // These are "user errors", we don't want to mark the plugin as failed
+ if (ex is not InvalidPluginOperationException)
+ this.State = PluginState.UnloadError;
+
Log.Error(ex, "Error while unloading {PluginName}", this.InternalName);
throw;
From 667ae312c56b217f8245f1683de7ca76f3f5c8dd Mon Sep 17 00:00:00 2001
From: goat <16760685+goaaats@users.noreply.github.com>
Date: Mon, 23 Dec 2024 21:15:03 +0100
Subject: [PATCH 10/88] some readme housekeeping
---
README.md | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index 8a925f1c6..bbf9ee1ce 100644
--- a/README.md
+++ b/README.md
@@ -4,13 +4,18 @@
-Dalamud is a plugin development framework for FINAL FANTASY XIV that provides access to game data and native interoperability with the game itself to add functionality and quality-of-life.
+Dalamud is a plugin development framework for FFXIV that provides access to game data and native interoperability with the game itself to add functionality and quality-of-life.
-It is meant to be used in conjunction with [FFXIVQuickLauncher](https://github.com/goatcorp/FFXIVQuickLauncher), which manages and launches Dalamud for you. __It is generally not recommended for users to try to run Dalamud manually as there are multiple dependencies and assumed folder paths.__
+It is meant to be used in conjunction with [XIVLauncher](https://github.com/goatcorp/FFXIVQuickLauncher), which manages and launches Dalamud for you. __It is generally not recommended for end users to try to run Dalamud manually as XIVLauncher manages multiple required dependencies.__
## Hold Up!
+
If you are just trying to **use** Dalamud, you don't need to do anything on this page - please [download XIVLauncher](https://goatcorp.github.io/) from its official page and follow the setup instructions.
+## Building and testing locally
+
+Please check the [docs page on building Dalamud](https://dalamud.dev/building) for more information and required dependencies.
+
## Plugin development
Dalamud features a growing API for in-game plugin development with game data and chat access and overlays.
Please see our [Developer FAQ](https://goatcorp.github.io/faq/development) and the [API documentation](https://dalamud.dev) for more details.
@@ -34,15 +39,6 @@ Dalamud can be loaded via DLL injection, or by rewriting a process' entrypoint.
| *Dalamud* (C#) | Core API, game bindings, plugin framework |
| *Dalamud.CorePlugin* (C#) | Testbed plugin that can access Dalamud internals, to prototype new Dalamud features |
-## Branches
-
-We are currently working from the following branches.
-
-| Name | API Level | Purpose | .NET Version | Track |
-|----------|-----------|------------------------------------------------------------|----------------------------|-------------------|
-| *master* | **9** | Current release branch | .NET 8.0.0 (November 2023) | Release & Staging |
-| *api10* | **10** | Next major version, slated for release alongside Patch 7.0 | .NET 8.0.0 (November 2023) | api10 |
-
##### Final Fantasy XIV © 2010-2021 SQUARE ENIX CO., LTD. All Rights Reserved. We are not affiliated with SQUARE ENIX CO., LTD. in any way.
From 5a2473293d28a076835d02e9ec1f446924109952 Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 23 Dec 2024 22:00:57 +0100
Subject: [PATCH 11/88] reorganize solution a bit
---
Dalamud.sln | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/Dalamud.sln b/Dalamud.sln
index 22cc59a8d..5d4b0737f 100644
--- a/Dalamud.sln
+++ b/Dalamud.sln
@@ -6,11 +6,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
+ tools\BannedSymbols.txt = tools\BannedSymbols.txt
targets\Dalamud.Plugin.Bootstrap.targets = targets\Dalamud.Plugin.Bootstrap.targets
targets\Dalamud.Plugin.targets = targets\Dalamud.Plugin.targets
- Directory.Build.props = Directory.Build.props
- tools\BannedSymbols.txt = tools\BannedSymbols.txt
tools\dalamud.ruleset = tools\dalamud.ruleset
+ Directory.Build.props = Directory.Build.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "build", "build\build.csproj", "{94E5B016-02B1-459B-97D9-E783F28764B2}"
@@ -25,7 +25,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Dalamud.Injector.Boot", "Da
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dalamud.Test", "Dalamud.Test\Dalamud.Test.csproj", "{C8004563-1806-4329-844F-0EF6274291FC}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Interface", "Interface", "{E15BDA6D-E881-4482-94BA-BE5527E917FF}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dependencies", "Dependencies", "{E15BDA6D-E881-4482-94BA-BE5527E917FF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImGui.NET-472", "lib\ImGuiScene\deps\ImGui.NET\src\ImGui.NET-472\ImGui.NET-472.csproj", "{0483026E-C6CE-4B1A-AA68-46544C08140B}"
EndProject
@@ -49,6 +49,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InteropGenerator", "lib\FFX
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InteropGenerator.Runtime", "lib\FFXIVClientStructs\InteropGenerator.Runtime\InteropGenerator.Runtime.csproj", "{A6AA1C3F-9470-4922-9D3F-D4549657AB22}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Injector", "Injector", "{19775C83-7117-4A5F-AA00-18889F46A490}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utilities", "Utilities", "{8F079208-C227-4D96-9427-2BEBE0003944}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -97,6 +101,10 @@ Global
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E0D51896-604F-4B40-8CFE-51941607B3A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E0D51896-604F-4B40-8CFE-51941607B3A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E0D51896-604F-4B40-8CFE-51941607B3A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E0D51896-604F-4B40-8CFE-51941607B3A1}.Release|Any CPU.Build.0 = Release|Any CPU
{317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|Any CPU.ActiveCfg = Debug|x64
{317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|Any CPU.Build.0 = Debug|x64
{317A264C-920B-44A1-8A34-F3A6827B0705}.Release|Any CPU.ActiveCfg = Release|x64
@@ -117,19 +125,20 @@ Global
{A6AA1C3F-9470-4922-9D3F-D4549657AB22}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A6AA1C3F-9470-4922-9D3F-D4549657AB22}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A6AA1C3F-9470-4922-9D3F-D4549657AB22}.Release|Any CPU.Build.0 = Release|Any CPU
- {E0D51896-604F-4B40-8CFE-51941607B3A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {E0D51896-604F-4B40-8CFE-51941607B3A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {E0D51896-604F-4B40-8CFE-51941607B3A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {E0D51896-604F-4B40-8CFE-51941607B3A1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
+ {5B832F73-5F54-4ADC-870F-D0095EF72C9A} = {19775C83-7117-4A5F-AA00-18889F46A490}
+ {8874326B-E755-4D13-90B4-59AB263A3E6B} = {19775C83-7117-4A5F-AA00-18889F46A490}
{0483026E-C6CE-4B1A-AA68-46544C08140B} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
{C0E7E797-4FBF-4F46-BC57-463F3719BA7A} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
{2F7FF0A8-B619-4572-86C7-71E46FE22FB8} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
+ {4AFDB34A-7467-4D41-B067-53BC4101D9D0} = {8F079208-C227-4D96-9427-2BEBE0003944}
{C9B87BD7-AF49-41C3-91F1-D550ADEB7833} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
+ {E0D51896-604F-4B40-8CFE-51941607B3A1} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
+ {A568929D-6FF6-4DFA-9D14-5D7DC08FA5E0} = {8F079208-C227-4D96-9427-2BEBE0003944}
{3620414C-7DFC-423E-929F-310E19F5D930} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
{A6AA1C3F-9470-4922-9D3F-D4549657AB22} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
EndGlobalSection
From 9616573f402af7ccb0b0873e788737240903a4bd Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 23 Dec 2024 22:36:31 +0100
Subject: [PATCH 12/88] reference and add vcxproj for cimgui, cimplot,
cimguizmo
---
.gitmodules | 9 ++
Dalamud.sln | 41 ++++-
external/Directory.Build.props | 3 +
external/cimgui/cimgui.vcxproj | 158 ++++++++++++++++++
external/cimgui/cimgui.vcxproj.filters | 45 ++++++
external/cimguizmo/cimguizmo.vcxproj | 162 +++++++++++++++++++
external/cimguizmo/cimguizmo.vcxproj.filters | 57 +++++++
external/cimplot/cimplot.vcxproj | 160 ++++++++++++++++++
external/cimplot/cimplot.vcxproj.filters | 51 ++++++
lib/cimgui | 1 +
lib/cimguizmo | 1 +
lib/cimplot | 1 +
12 files changed, 682 insertions(+), 7 deletions(-)
create mode 100644 external/Directory.Build.props
create mode 100644 external/cimgui/cimgui.vcxproj
create mode 100644 external/cimgui/cimgui.vcxproj.filters
create mode 100644 external/cimguizmo/cimguizmo.vcxproj
create mode 100644 external/cimguizmo/cimguizmo.vcxproj.filters
create mode 100644 external/cimplot/cimplot.vcxproj
create mode 100644 external/cimplot/cimplot.vcxproj.filters
create mode 160000 lib/cimgui
create mode 160000 lib/cimguizmo
create mode 160000 lib/cimplot
diff --git a/.gitmodules b/.gitmodules
index dd184b54e..227653d48 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -10,3 +10,12 @@
[submodule "lib/TsudaKageyu-minhook"]
path = lib/TsudaKageyu-minhook
url = https://github.com/TsudaKageyu/minhook.git
+[submodule "lib/cimgui"]
+ path = lib/cimgui
+ url = https://github.com/goatcorp/gc-cimgui
+[submodule "lib/cimplot"]
+ path = lib/cimplot
+ url = https://github.com/goatcorp/gc-cimplot
+[submodule "lib/cimguizmo"]
+ path = lib/cimguizmo
+ url = https://github.com/goatcorp/gc-cimguizmo
diff --git a/Dalamud.sln b/Dalamud.sln
index 5d4b0737f..49fc9e011 100644
--- a/Dalamud.sln
+++ b/Dalamud.sln
@@ -53,6 +53,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Injector", "Injector", "{19
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utilities", "Utilities", "{8F079208-C227-4D96-9427-2BEBE0003944}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cimgui", "external\cimgui\cimgui.vcxproj", "{8430077C-F736-4246-A052-8EA1CECE844E}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "imgui", "imgui", "{DBE5345E-6594-4A59-B183-1C3D5592269D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CS", "CS", "{8BBACF2D-7AB8-4610-A115-0E363D35C291}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cimplot", "external\cimplot\cimplot.vcxproj", "{76CAA246-C405-4A8C-B0AE-F4A0EF3D4E16}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cimguizmo", "external\cimguizmo\cimguizmo.vcxproj", "{F258347D-31BE-4605-98CE-40E43BDF6F9D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -125,6 +135,18 @@ Global
{A6AA1C3F-9470-4922-9D3F-D4549657AB22}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A6AA1C3F-9470-4922-9D3F-D4549657AB22}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A6AA1C3F-9470-4922-9D3F-D4549657AB22}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8430077C-F736-4246-A052-8EA1CECE844E}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {8430077C-F736-4246-A052-8EA1CECE844E}.Debug|Any CPU.Build.0 = Debug|x64
+ {8430077C-F736-4246-A052-8EA1CECE844E}.Release|Any CPU.ActiveCfg = Release|x64
+ {8430077C-F736-4246-A052-8EA1CECE844E}.Release|Any CPU.Build.0 = Release|x64
+ {76CAA246-C405-4A8C-B0AE-F4A0EF3D4E16}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {76CAA246-C405-4A8C-B0AE-F4A0EF3D4E16}.Debug|Any CPU.Build.0 = Debug|x64
+ {76CAA246-C405-4A8C-B0AE-F4A0EF3D4E16}.Release|Any CPU.ActiveCfg = Release|x64
+ {76CAA246-C405-4A8C-B0AE-F4A0EF3D4E16}.Release|Any CPU.Build.0 = Release|x64
+ {F258347D-31BE-4605-98CE-40E43BDF6F9D}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {F258347D-31BE-4605-98CE-40E43BDF6F9D}.Debug|Any CPU.Build.0 = Debug|x64
+ {F258347D-31BE-4605-98CE-40E43BDF6F9D}.Release|Any CPU.ActiveCfg = Release|x64
+ {F258347D-31BE-4605-98CE-40E43BDF6F9D}.Release|Any CPU.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -132,15 +154,20 @@ Global
GlobalSection(NestedProjects) = preSolution
{5B832F73-5F54-4ADC-870F-D0095EF72C9A} = {19775C83-7117-4A5F-AA00-18889F46A490}
{8874326B-E755-4D13-90B4-59AB263A3E6B} = {19775C83-7117-4A5F-AA00-18889F46A490}
- {0483026E-C6CE-4B1A-AA68-46544C08140B} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
- {C0E7E797-4FBF-4F46-BC57-463F3719BA7A} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
- {2F7FF0A8-B619-4572-86C7-71E46FE22FB8} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
+ {0483026E-C6CE-4B1A-AA68-46544C08140B} = {DBE5345E-6594-4A59-B183-1C3D5592269D}
+ {C0E7E797-4FBF-4F46-BC57-463F3719BA7A} = {DBE5345E-6594-4A59-B183-1C3D5592269D}
+ {2F7FF0A8-B619-4572-86C7-71E46FE22FB8} = {DBE5345E-6594-4A59-B183-1C3D5592269D}
{4AFDB34A-7467-4D41-B067-53BC4101D9D0} = {8F079208-C227-4D96-9427-2BEBE0003944}
- {C9B87BD7-AF49-41C3-91F1-D550ADEB7833} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
- {E0D51896-604F-4B40-8CFE-51941607B3A1} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
+ {C9B87BD7-AF49-41C3-91F1-D550ADEB7833} = {8BBACF2D-7AB8-4610-A115-0E363D35C291}
+ {E0D51896-604F-4B40-8CFE-51941607B3A1} = {8BBACF2D-7AB8-4610-A115-0E363D35C291}
{A568929D-6FF6-4DFA-9D14-5D7DC08FA5E0} = {8F079208-C227-4D96-9427-2BEBE0003944}
- {3620414C-7DFC-423E-929F-310E19F5D930} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
- {A6AA1C3F-9470-4922-9D3F-D4549657AB22} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
+ {3620414C-7DFC-423E-929F-310E19F5D930} = {8BBACF2D-7AB8-4610-A115-0E363D35C291}
+ {A6AA1C3F-9470-4922-9D3F-D4549657AB22} = {8BBACF2D-7AB8-4610-A115-0E363D35C291}
+ {8430077C-F736-4246-A052-8EA1CECE844E} = {DBE5345E-6594-4A59-B183-1C3D5592269D}
+ {DBE5345E-6594-4A59-B183-1C3D5592269D} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
+ {8BBACF2D-7AB8-4610-A115-0E363D35C291} = {E15BDA6D-E881-4482-94BA-BE5527E917FF}
+ {76CAA246-C405-4A8C-B0AE-F4A0EF3D4E16} = {DBE5345E-6594-4A59-B183-1C3D5592269D}
+ {F258347D-31BE-4605-98CE-40E43BDF6F9D} = {DBE5345E-6594-4A59-B183-1C3D5592269D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {79B65AC9-C940-410E-AB61-7EA7E12C7599}
diff --git a/external/Directory.Build.props b/external/Directory.Build.props
new file mode 100644
index 000000000..f719442cd
--- /dev/null
+++ b/external/Directory.Build.props
@@ -0,0 +1,3 @@
+
+
+
diff --git a/external/cimgui/cimgui.vcxproj b/external/cimgui/cimgui.vcxproj
new file mode 100644
index 000000000..c5663fa05
--- /dev/null
+++ b/external/cimgui/cimgui.vcxproj
@@ -0,0 +1,158 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 17.0
+ Win32Proj
+ {8430077c-f736-4246-a052-8ea1cece844e}
+ cimgui
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+ Windows
+ true
+ false
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+ Windows
+ true
+ true
+ true
+ false
+
+
+
+
+ Level3
+ true
+ _DEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ $(SolutionDir)lib\cimgui\imgui;%(AdditionalIncludeDirectories)
+
+
+ Windows
+ true
+ false
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+ Windows
+ true
+ true
+ true
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/external/cimgui/cimgui.vcxproj.filters b/external/cimgui/cimgui.vcxproj.filters
new file mode 100644
index 000000000..d48c361f1
--- /dev/null
+++ b/external/cimgui/cimgui.vcxproj.filters
@@ -0,0 +1,45 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/external/cimguizmo/cimguizmo.vcxproj b/external/cimguizmo/cimguizmo.vcxproj
new file mode 100644
index 000000000..3fe6fb073
--- /dev/null
+++ b/external/cimguizmo/cimguizmo.vcxproj
@@ -0,0 +1,162 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 17.0
+ Win32Proj
+ {F258347D-31BE-4605-98CE-40E43BDF6F9D}
+ cimplot
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;CIMGUIZMO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+ Windows
+ true
+ false
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;CIMGUIZMO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+ Windows
+ true
+ true
+ true
+ false
+
+
+
+
+ Level3
+ true
+ _DEBUG;CIMGUIZMO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ $(SolutionDir)lib\cimgui\imgui;$(SolutionDir)lib\cimguizmo\ImGuizmo;$(SolutionDir)lib\cimgui;%(AdditionalIncludeDirectories)
+
+
+ Windows
+ true
+ false
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;CIMGUIZMO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+ Windows
+ true
+ true
+ true
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/external/cimguizmo/cimguizmo.vcxproj.filters b/external/cimguizmo/cimguizmo.vcxproj.filters
new file mode 100644
index 000000000..f954dcc2c
--- /dev/null
+++ b/external/cimguizmo/cimguizmo.vcxproj.filters
@@ -0,0 +1,57 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/external/cimplot/cimplot.vcxproj b/external/cimplot/cimplot.vcxproj
new file mode 100644
index 000000000..872448ea8
--- /dev/null
+++ b/external/cimplot/cimplot.vcxproj
@@ -0,0 +1,160 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 17.0
+ Win32Proj
+ {76caa246-c405-4a8c-b0ae-f4a0ef3d4e16}
+ cimplot
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;CIMPLOT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+ Windows
+ true
+ false
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;CIMPLOT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+ Windows
+ true
+ true
+ true
+ false
+
+
+
+
+ Level3
+ true
+ _DEBUG;CIMPLOT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ $(SolutionDir)lib\cimgui\imgui;$(SolutionDir)lib\cimplot\implot;$(SolutionDir)lib\cimgui;%(AdditionalIncludeDirectories)
+
+
+ Windows
+ true
+ false
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;CIMPLOT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+ Windows
+ true
+ true
+ true
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/external/cimplot/cimplot.vcxproj.filters b/external/cimplot/cimplot.vcxproj.filters
new file mode 100644
index 000000000..ad8bfd11b
--- /dev/null
+++ b/external/cimplot/cimplot.vcxproj.filters
@@ -0,0 +1,51 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/lib/cimgui b/lib/cimgui
new file mode 160000
index 000000000..7b4955bbd
--- /dev/null
+++ b/lib/cimgui
@@ -0,0 +1 @@
+Subproject commit 7b4955bbd8f7bc6c022d39503dc806fa53a6a590
diff --git a/lib/cimguizmo b/lib/cimguizmo
new file mode 160000
index 000000000..dbad4fdb4
--- /dev/null
+++ b/lib/cimguizmo
@@ -0,0 +1 @@
+Subproject commit dbad4fdb4d465e1f48d20c4c54a20925095297b0
diff --git a/lib/cimplot b/lib/cimplot
new file mode 160000
index 000000000..939f8f36d
--- /dev/null
+++ b/lib/cimplot
@@ -0,0 +1 @@
+Subproject commit 939f8f36deebd895f6cda522ee4bb2b798920935
From 43ab6bd24fdb80bed9824ffcde0c409c5207150c Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 23 Dec 2024 22:39:55 +0100
Subject: [PATCH 13/88] remove win32 targets
---
external/cimgui/cimgui.vcxproj | 61 ----------------------------
external/cimguizmo/cimguizmo.vcxproj | 61 ----------------------------
external/cimplot/cimplot.vcxproj | 61 ----------------------------
3 files changed, 183 deletions(-)
diff --git a/external/cimgui/cimgui.vcxproj b/external/cimgui/cimgui.vcxproj
index c5663fa05..7c75fd853 100644
--- a/external/cimgui/cimgui.vcxproj
+++ b/external/cimgui/cimgui.vcxproj
@@ -1,14 +1,6 @@
-
- Debug
- Win32
-
-
- Release
- Win32
-
Debug
x64
@@ -38,19 +30,6 @@
10.0
-
- DynamicLibrary
- true
- v143
- Unicode
-
-
- DynamicLibrary
- false
- v143
- true
- Unicode
-
DynamicLibrary
true
@@ -69,12 +48,6 @@
-
-
-
-
-
-
@@ -82,40 +55,6 @@
-
-
- Level3
- true
- WIN32;_DEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
- true
- Use
- pch.h
-
-
- Windows
- true
- false
-
-
-
-
- Level3
- true
- true
- true
- WIN32;NDEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
- true
- Use
- pch.h
-
-
- Windows
- true
- true
- true
- false
-
-
Level3
diff --git a/external/cimguizmo/cimguizmo.vcxproj b/external/cimguizmo/cimguizmo.vcxproj
index 3fe6fb073..11200ad72 100644
--- a/external/cimguizmo/cimguizmo.vcxproj
+++ b/external/cimguizmo/cimguizmo.vcxproj
@@ -1,14 +1,6 @@
-
- Debug
- Win32
-
-
- Release
- Win32
-
Debug
x64
@@ -42,19 +34,6 @@
10.0
-
- DynamicLibrary
- true
- v143
- Unicode
-
-
- DynamicLibrary
- false
- v143
- true
- Unicode
-
DynamicLibrary
true
@@ -73,12 +52,6 @@
-
-
-
-
-
-
@@ -86,40 +59,6 @@
-
-
- Level3
- true
- WIN32;_DEBUG;CIMGUIZMO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
- true
- Use
- pch.h
-
-
- Windows
- true
- false
-
-
-
-
- Level3
- true
- true
- true
- WIN32;NDEBUG;CIMGUIZMO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
- true
- Use
- pch.h
-
-
- Windows
- true
- true
- true
- false
-
-
Level3
diff --git a/external/cimplot/cimplot.vcxproj b/external/cimplot/cimplot.vcxproj
index 872448ea8..eacebe3de 100644
--- a/external/cimplot/cimplot.vcxproj
+++ b/external/cimplot/cimplot.vcxproj
@@ -1,14 +1,6 @@
-
- Debug
- Win32
-
-
- Release
- Win32
-
Debug
x64
@@ -40,19 +32,6 @@
10.0
-
- DynamicLibrary
- true
- v143
- Unicode
-
-
- DynamicLibrary
- false
- v143
- true
- Unicode
-
DynamicLibrary
true
@@ -71,12 +50,6 @@
-
-
-
-
-
-
@@ -84,40 +57,6 @@
-
-
- Level3
- true
- WIN32;_DEBUG;CIMPLOT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
- true
- Use
- pch.h
-
-
- Windows
- true
- false
-
-
-
-
- Level3
- true
- true
- true
- WIN32;NDEBUG;CIMPLOT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
- true
- Use
- pch.h
-
-
- Windows
- true
- true
- true
- false
-
-
Level3
From 371f1bfa1895eeb42db28d51536705649770b79f Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 23 Dec 2024 23:17:33 +0100
Subject: [PATCH 14/88] comment out kizer hack for now, need to move to natives
---
Dalamud/Interface/Internal/ImGuiDrawListFixProvider.cs | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Dalamud/Interface/Internal/ImGuiDrawListFixProvider.cs b/Dalamud/Interface/Internal/ImGuiDrawListFixProvider.cs
index a682ed215..6ba5a1d94 100644
--- a/Dalamud/Interface/Internal/ImGuiDrawListFixProvider.cs
+++ b/Dalamud/Interface/Internal/ImGuiDrawListFixProvider.cs
@@ -39,6 +39,8 @@ internal sealed unsafe class ImGuiDrawListFixProvider : IInternalDisposableServi
private ImGuiDrawListFixProvider(InterfaceManager.InterfaceManagerWithScene imws)
{
// Force cimgui.dll to be loaded.
+ // TODO(goat): Apply fixes in natives
+ /*
_ = ImGui.GetCurrentContext();
var cimgui = Process.GetCurrentProcess().Modules.Cast()
.First(x => x.ModuleName == "cimgui.dll")
@@ -56,6 +58,7 @@ internal sealed unsafe class ImGuiDrawListFixProvider : IInternalDisposableServi
this.hookImDrawListAddPolyline.Enable();
this.hookImDrawListAddRectFilled.Enable();
this.hookImDrawListAddImageRounded.Enable();
+ */
}
private delegate void ImDrawListAddPolyLine(
From f696f7250f1f3232ab5eefbe955a77b2667b442c Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 23 Dec 2024 23:24:13 +0100
Subject: [PATCH 15/88] shoddy include in dalamud build for now
---
Dalamud/Dalamud.csproj | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index a6ac07227..610bd7f84 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -103,6 +103,44 @@
+
+
+
+
+
+
+
+
+ %(RecursiveDir)%(FileName)%(Extension)
+ PreserveNewest
+
+
+
+ %(RecursiveDir)%(FileName)%(Extension)
+ PreserveNewest
+
+
+
+ %(RecursiveDir)%(FileName)%(Extension)
+ PreserveNewest
+
+
+
+ %(RecursiveDir)%(FileName)%(Extension)
+ PreserveNewest
+
+
+
+ %(RecursiveDir)%(FileName)%(Extension)
+ PreserveNewest
+
+
+
+ %(RecursiveDir)%(FileName)%(Extension)
+ PreserveNewest
+
+
+
From 1714191711da7e07e5edfd416b505497ba363ed5 Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 23 Dec 2024 23:25:21 +0100
Subject: [PATCH 16/88] attest imgui DLLs
---
.github/workflows/main.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 669d6255a..930adf8ed 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -55,6 +55,7 @@ jobs:
bin/Release/Dalamud.*.dll
bin/Release/Dalamud.*.exe
bin/Release/FFXIVClientStructs.dll
+ bin/Release/cim*.dll
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
From 7629cac8af3c800bf5a26f8b0c912d0526c8bac1 Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 23 Dec 2024 23:29:16 +0100
Subject: [PATCH 17/88] use ImGuiScene without shipped binaries
---
lib/ImGuiScene | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/ImGuiScene b/lib/ImGuiScene
index b0d41471b..d336b20a8 160000
--- a/lib/ImGuiScene
+++ b/lib/ImGuiScene
@@ -1 +1 @@
-Subproject commit b0d41471b7ef3d69daaf6d862eb74e7e00a25651
+Subproject commit d336b20a85ea48723a98681b18bdfe14a56a3403
From 87525091c903895dba88ec72655301c7e48c5151 Mon Sep 17 00:00:00 2001
From: goat
Date: Tue, 24 Dec 2024 01:52:38 +0100
Subject: [PATCH 18/88] make it work with nuke
---
.nuke/build.schema.json | 8 ++++
Dalamud.sln | 5 +++
Dalamud/Dalamud.csproj | 54 +++++++-------------------
build/DalamudBuild.cs | 58 +++++++++++++++++++++++++++-
external/cimgui/cimgui.vcxproj | 5 ++-
external/cimguizmo/cimguizmo.vcxproj | 5 ++-
external/cimplot/cimplot.vcxproj | 5 ++-
7 files changed, 97 insertions(+), 43 deletions(-)
diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json
index 497f2b89a..e7e1a446a 100644
--- a/.nuke/build.schema.json
+++ b/.nuke/build.schema.json
@@ -78,9 +78,13 @@
"enum": [
"Clean",
"Compile",
+ "CompileCImGui",
+ "CompileCImGuizmo",
+ "CompileCImPlot",
"CompileDalamud",
"CompileDalamudBoot",
"CompileDalamudCrashHandler",
+ "CompileImGuiNatives",
"CompileInjector",
"CompileInjectorBoot",
"Restore",
@@ -100,9 +104,13 @@
"enum": [
"Clean",
"Compile",
+ "CompileCImGui",
+ "CompileCImGuizmo",
+ "CompileCImPlot",
"CompileDalamud",
"CompileDalamudBoot",
"CompileDalamudCrashHandler",
+ "CompileImGuiNatives",
"CompileInjector",
"CompileInjectorBoot",
"Restore",
diff --git a/Dalamud.sln b/Dalamud.sln
index 49fc9e011..5b6f56c6e 100644
--- a/Dalamud.sln
+++ b/Dalamud.sln
@@ -16,6 +16,11 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "build", "build\build.csproj", "{94E5B016-02B1-459B-97D9-E783F28764B2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dalamud", "Dalamud\Dalamud.csproj", "{B92DAB43-2279-4A2C-96E3-D9D5910EDBEA}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76CAA246-C405-4A8C-B0AE-F4A0EF3D4E16} = {76CAA246-C405-4A8C-B0AE-F4A0EF3D4E16}
+ {8430077C-F736-4246-A052-8EA1CECE844E} = {8430077C-F736-4246-A052-8EA1CECE844E}
+ {F258347D-31BE-4605-98CE-40E43BDF6F9D} = {F258347D-31BE-4605-98CE-40E43BDF6F9D}
+ EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Dalamud.Boot", "Dalamud.Boot\Dalamud.Boot.vcxproj", "{55198DC3-A03D-408E-A8EB-2077780C8576}"
EndProject
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index 610bd7f84..1cd9fc336 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -3,7 +3,7 @@
net8.0-windows
x64
- x64;AnyCPU
+ x64
12.0
True
@@ -103,44 +103,6 @@
-
-
-
-
-
-
-
-
- %(RecursiveDir)%(FileName)%(Extension)
- PreserveNewest
-
-
-
- %(RecursiveDir)%(FileName)%(Extension)
- PreserveNewest
-
-
-
- %(RecursiveDir)%(FileName)%(Extension)
- PreserveNewest
-
-
-
- %(RecursiveDir)%(FileName)%(Extension)
- PreserveNewest
-
-
-
- %(RecursiveDir)%(FileName)%(Extension)
- PreserveNewest
-
-
-
- %(RecursiveDir)%(FileName)%(Extension)
- PreserveNewest
-
-
-
@@ -243,4 +205,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/DalamudBuild.cs b/build/DalamudBuild.cs
index d704d54e0..6340c36fa 100644
--- a/build/DalamudBuild.cs
+++ b/build/DalamudBuild.cs
@@ -47,6 +47,14 @@ public class DalamudBuild : NukeBuild
AbsolutePath TestProjectDir => RootDirectory / "Dalamud.Test";
AbsolutePath TestProjectFile => TestProjectDir / "Dalamud.Test.csproj";
+ AbsolutePath ExternalsDir => RootDirectory / "external";
+ AbsolutePath CImGuiDir => ExternalsDir / "cimgui";
+ AbsolutePath CImGuiProjectFile => CImGuiDir / "cimgui.vcxproj";
+ AbsolutePath CImPlotDir => ExternalsDir / "cimplot";
+ AbsolutePath CImPlotProjectFile => CImPlotDir / "cimplot.vcxproj";
+ AbsolutePath CImGuizmoDir => ExternalsDir / "cimguizmo";
+ AbsolutePath CImGuizmoProjectFile => CImGuizmoDir / "cimguizmo.vcxproj";
+
AbsolutePath ArtifactsDirectory => RootDirectory / "bin" / Configuration;
private static AbsolutePath LibraryDirectory => RootDirectory / "lib";
@@ -59,9 +67,42 @@ public class DalamudBuild : NukeBuild
DotNetTasks.DotNetRestore(s => s
.SetProjectFile(Solution));
});
-
+
+ Target CompileCImGui => _ => _
+ .Executes(() =>
+ {
+ MSBuildTasks.MSBuild(s => s
+ .SetTargetPath(CImGuiProjectFile)
+ .SetConfiguration(Configuration)
+ .SetTargetPlatform(MSBuildTargetPlatform.x64));
+ });
+
+ Target CompileCImPlot => _ => _
+ .Executes(() =>
+ {
+ MSBuildTasks.MSBuild(s => s
+ .SetTargetPath(CImPlotProjectFile)
+ .SetConfiguration(Configuration)
+ .SetTargetPlatform(MSBuildTargetPlatform.x64));
+ });
+
+ Target CompileCImGuizmo => _ => _
+ .Executes(() =>
+ {
+ MSBuildTasks.MSBuild(s => s
+ .SetTargetPath(CImGuizmoProjectFile)
+ .SetConfiguration(Configuration)
+ .SetTargetPlatform(MSBuildTargetPlatform.x64));
+ });
+
+ Target CompileImGuiNatives => _ => _
+ .DependsOn(CompileCImGui)
+ .DependsOn(CompileCImPlot)
+ .DependsOn(CompileCImGuizmo);
+
Target CompileDalamud => _ => _
.DependsOn(Restore)
+ .DependsOn(CompileImGuiNatives)
.Executes(() =>
{
DotNetTasks.DotNetBuild(s =>
@@ -138,6 +179,21 @@ public class DalamudBuild : NukeBuild
Target Clean => _ => _
.Executes(() =>
{
+ MSBuildTasks.MSBuild(s => s
+ .SetProjectFile(CImGuiProjectFile)
+ .SetConfiguration(Configuration)
+ .SetTargets("Clean"));
+
+ MSBuildTasks.MSBuild(s => s
+ .SetProjectFile(CImPlotProjectFile)
+ .SetConfiguration(Configuration)
+ .SetTargets("Clean"));
+
+ MSBuildTasks.MSBuild(s => s
+ .SetProjectFile(CImGuizmoProjectFile)
+ .SetConfiguration(Configuration)
+ .SetTargets("Clean"));
+
DotNetTasks.DotNetClean(s => s
.SetProject(DalamudProjectFile)
.SetConfiguration(Configuration));
diff --git a/external/cimgui/cimgui.vcxproj b/external/cimgui/cimgui.vcxproj
index 7c75fd853..12bb376f8 100644
--- a/external/cimgui/cimgui.vcxproj
+++ b/external/cimgui/cimgui.vcxproj
@@ -55,6 +55,9 @@
+
+ ..\$(Platform)\$(Configuration)\
+
Level3
@@ -64,7 +67,7 @@
NotUsing
- $(SolutionDir)lib\cimgui\imgui;%(AdditionalIncludeDirectories)
+ ..\..\lib\cimgui\imgui;%(AdditionalIncludeDirectories)
Windows
diff --git a/external/cimguizmo/cimguizmo.vcxproj b/external/cimguizmo/cimguizmo.vcxproj
index 11200ad72..849cbfba5 100644
--- a/external/cimguizmo/cimguizmo.vcxproj
+++ b/external/cimguizmo/cimguizmo.vcxproj
@@ -59,6 +59,9 @@
+
+ ..\$(Platform)\$(Configuration)\
+
Level3
@@ -68,7 +71,7 @@
NotUsing
- $(SolutionDir)lib\cimgui\imgui;$(SolutionDir)lib\cimguizmo\ImGuizmo;$(SolutionDir)lib\cimgui;%(AdditionalIncludeDirectories)
+ ..\..\lib\cimgui\imgui;..\..\lib\cimguizmo\ImGuizmo;..\..\lib\cimgui;%(AdditionalIncludeDirectories)
Windows
diff --git a/external/cimplot/cimplot.vcxproj b/external/cimplot/cimplot.vcxproj
index eacebe3de..3477ab262 100644
--- a/external/cimplot/cimplot.vcxproj
+++ b/external/cimplot/cimplot.vcxproj
@@ -57,6 +57,9 @@
+
+ ..\$(Platform)\$(Configuration)\
+
Level3
@@ -66,7 +69,7 @@
NotUsing
- $(SolutionDir)lib\cimgui\imgui;$(SolutionDir)lib\cimplot\implot;$(SolutionDir)lib\cimgui;%(AdditionalIncludeDirectories)
+ ..\..\lib\cimgui\imgui;..\..\lib\cimplot\implot;..\..\lib\cimgui;%(AdditionalIncludeDirectories)
Windows
From 419b62b2c981e446f6949b16175b662391ec9ce4 Mon Sep 17 00:00:00 2001
From: goat
Date: Tue, 24 Dec 2024 02:48:42 +0100
Subject: [PATCH 19/88] fix release build
---
external/cimgui/cimgui.vcxproj | 18 ++++++++++--------
external/cimguizmo/cimguizmo.vcxproj | 16 +++++++++-------
external/cimplot/cimplot.vcxproj | 16 +++++++++-------
3 files changed, 28 insertions(+), 22 deletions(-)
diff --git a/external/cimgui/cimgui.vcxproj b/external/cimgui/cimgui.vcxproj
index 12bb376f8..c6109a131 100644
--- a/external/cimgui/cimgui.vcxproj
+++ b/external/cimgui/cimgui.vcxproj
@@ -55,19 +55,23 @@
-
+
..\$(Platform)\$(Configuration)\
+
+
+
+ ..\..\lib\cimgui\imgui;%(AdditionalIncludeDirectories)
+ NotUsing
+
+
+
Level3
true
_DEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1;%(PreprocessorDefinitions)
true
- NotUsing
-
-
- ..\..\lib\cimgui\imgui;%(AdditionalIncludeDirectories)
Windows
@@ -81,10 +85,8 @@
true
true
true
- NDEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ NDEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1;%(PreprocessorDefinitions)
true
- Use
- pch.h
Windows
diff --git a/external/cimguizmo/cimguizmo.vcxproj b/external/cimguizmo/cimguizmo.vcxproj
index 849cbfba5..56c085da3 100644
--- a/external/cimguizmo/cimguizmo.vcxproj
+++ b/external/cimguizmo/cimguizmo.vcxproj
@@ -59,19 +59,23 @@
-
+
..\$(Platform)\$(Configuration)\
+
+
+
+ ..\..\lib\cimgui\imgui;..\..\lib\cimguizmo\ImGuizmo;..\..\lib\cimgui;%(AdditionalIncludeDirectories)
+ NotUsing
+
+
+
Level3
true
_DEBUG;CIMGUIZMO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
- NotUsing
-
-
- ..\..\lib\cimgui\imgui;..\..\lib\cimguizmo\ImGuizmo;..\..\lib\cimgui;%(AdditionalIncludeDirectories)
Windows
@@ -87,8 +91,6 @@
true
NDEBUG;CIMGUIZMO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
- Use
- pch.h
Windows
diff --git a/external/cimplot/cimplot.vcxproj b/external/cimplot/cimplot.vcxproj
index 3477ab262..44bcf95bb 100644
--- a/external/cimplot/cimplot.vcxproj
+++ b/external/cimplot/cimplot.vcxproj
@@ -57,19 +57,23 @@
-
+
..\$(Platform)\$(Configuration)\
+
+
+
+ ..\..\lib\cimgui\imgui;..\..\lib\cimplot\implot;..\..\lib\cimgui;%(AdditionalIncludeDirectories)
+ NotUsing
+
+
+
Level3
true
_DEBUG;CIMPLOT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
- NotUsing
-
-
- ..\..\lib\cimgui\imgui;..\..\lib\cimplot\implot;..\..\lib\cimgui;%(AdditionalIncludeDirectories)
Windows
@@ -85,8 +89,6 @@
true
NDEBUG;CIMPLOT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
- Use
- pch.h
Windows
From c31fe0920fd1395b2e3f997471a6790646c067e4 Mon Sep 17 00:00:00 2001
From: goat
Date: Tue, 24 Dec 2024 03:44:31 +0100
Subject: [PATCH 20/88] remove hackfix hooks
---
.../Internal/ImGuiDrawListFixProvider.cs | 225 ------------------
lib/cimgui | 2 +-
2 files changed, 1 insertion(+), 226 deletions(-)
delete mode 100644 Dalamud/Interface/Internal/ImGuiDrawListFixProvider.cs
diff --git a/Dalamud/Interface/Internal/ImGuiDrawListFixProvider.cs b/Dalamud/Interface/Internal/ImGuiDrawListFixProvider.cs
deleted file mode 100644
index 6ba5a1d94..000000000
--- a/Dalamud/Interface/Internal/ImGuiDrawListFixProvider.cs
+++ /dev/null
@@ -1,225 +0,0 @@
-using System.Diagnostics;
-using System.Linq;
-using System.Numerics;
-
-using Dalamud.Hooking;
-
-using ImGuiNET;
-
-namespace Dalamud.Interface.Internal;
-
-///
-/// Fixes ImDrawList not correctly dealing with the current texture for that draw list not in tune with the global
-/// state. Currently, ImDrawList::AddPolyLine and ImDrawList::AddRectFilled are affected.
-///
-/// * The implementation for AddRectFilled is entirely replaced with the hook below.
-/// * The implementation for AddPolyLine is wrapped with Push/PopTextureID.
-///
-/// TODO:
-/// * imgui_draw.cpp:1433 ImDrawList::AddRectFilled
-/// The if block needs a PushTextureID(_Data->TexIdCommon)/PopTextureID() block,
-/// if _Data->TexIdCommon != _CmdHeader.TextureId.
-/// * imgui_draw.cpp:729 ImDrawList::AddPolyLine
-/// The if block always needs to call PushTextureID if the abovementioned condition is not met.
-/// Change push_texture_id to only have one condition.
-///
-[ServiceManager.EarlyLoadedService]
-internal sealed unsafe class ImGuiDrawListFixProvider : IInternalDisposableService
-{
- private const int CImGuiImDrawListAddPolyLineOffset = 0x589B0;
- private const int CImGuiImDrawListAddRectFilled = 0x59FD0;
- private const int CImGuiImDrawListAddImageRounded = 0x58390;
- private const int CImGuiImDrawListSharedDataTexIdCommonOffset = 0;
-
- private readonly Hook hookImDrawListAddPolyline;
- private readonly Hook hookImDrawListAddRectFilled;
- private readonly Hook hookImDrawListAddImageRounded;
-
- [ServiceManager.ServiceConstructor]
- private ImGuiDrawListFixProvider(InterfaceManager.InterfaceManagerWithScene imws)
- {
- // Force cimgui.dll to be loaded.
- // TODO(goat): Apply fixes in natives
- /*
- _ = ImGui.GetCurrentContext();
- var cimgui = Process.GetCurrentProcess().Modules.Cast()
- .First(x => x.ModuleName == "cimgui.dll")
- .BaseAddress;
-
- this.hookImDrawListAddPolyline = Hook.FromAddress(
- cimgui + CImGuiImDrawListAddPolyLineOffset,
- this.ImDrawListAddPolylineDetour);
- this.hookImDrawListAddRectFilled = Hook.FromAddress(
- cimgui + CImGuiImDrawListAddRectFilled,
- this.ImDrawListAddRectFilledDetour);
- this.hookImDrawListAddImageRounded = Hook.FromAddress(
- cimgui + CImGuiImDrawListAddImageRounded,
- this.ImDrawListAddImageRoundedDetour);
- this.hookImDrawListAddPolyline.Enable();
- this.hookImDrawListAddRectFilled.Enable();
- this.hookImDrawListAddImageRounded.Enable();
- */
- }
-
- private delegate void ImDrawListAddPolyLine(
- ImDrawListPtr drawListPtr,
- ref Vector2 points,
- int pointsCount,
- uint color,
- ImDrawFlags flags,
- float thickness);
-
- private delegate void ImDrawListAddRectFilled(
- ImDrawListPtr drawListPtr,
- ref Vector2 min,
- ref Vector2 max,
- uint col,
- float rounding,
- ImDrawFlags flags);
-
- private delegate void ImDrawListAddImageRounded(
- ImDrawListPtr drawListPtr,
- nint userTextureId, ref Vector2 xy0,
- ref Vector2 xy1,
- ref Vector2 uv0,
- ref Vector2 uv1,
- uint col,
- float rounding,
- ImDrawFlags flags);
-
- ///
- void IInternalDisposableService.DisposeService()
- {
- this.hookImDrawListAddPolyline.Dispose();
- this.hookImDrawListAddRectFilled.Dispose();
- this.hookImDrawListAddImageRounded.Dispose();
- }
-
- private static ImDrawFlags FixRectCornerFlags(ImDrawFlags flags)
- {
-#if !IMGUI_DISABLE_OBSOLETE_FUNCTIONS
- // Legacy Support for hard coded ~0 (used to be a suggested equivalent to ImDrawCornerFlags_All)
- // ~0 --> ImDrawFlags_RoundCornersAll or 0
- if ((int)flags == ~0)
- return ImDrawFlags.RoundCornersAll;
-
- // Legacy Support for hard coded 0x01 to 0x0F (matching 15 out of 16 old flags combinations)
- // 0x01 --> ImDrawFlags_RoundCornersTopLeft (VALUE 0x01 OVERLAPS ImDrawFlags_Closed but ImDrawFlags_Closed is never valid in this path!)
- // 0x02 --> ImDrawFlags_RoundCornersTopRight
- // 0x03 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight
- // 0x04 --> ImDrawFlags_RoundCornersBotLeft
- // 0x05 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBotLeft
- // ...
- // 0x0F --> ImDrawFlags_RoundCornersAll or 0
- // (See all values in ImDrawCornerFlags_)
- if ((int)flags >= 0x01 && (int)flags <= 0x0F)
- return (ImDrawFlags)((int)flags << 4);
-
- // We cannot support hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundCornersNone or use 'float rounding = 0.0f'
-#endif
-
- // If this triggers, please update your code replacing hardcoded values with new ImDrawFlags_RoundCorners* values.
- // Note that ImDrawFlags_Closed (== 0x01) is an invalid flag for AddRect(), AddRectFilled(), PathRect() etc...
- if (((int)flags & 0x0F) != 0)
- throw new ArgumentException("Misuse of legacy hardcoded ImDrawCornerFlags values!");
-
- if ((flags & ImDrawFlags.RoundCornersMask) == 0)
- flags |= ImDrawFlags.RoundCornersAll;
-
- return flags;
- }
-
- private void ImDrawListAddRectFilledDetour(
- ImDrawListPtr drawListPtr,
- ref Vector2 min,
- ref Vector2 max,
- uint col,
- float rounding,
- ImDrawFlags flags)
- {
- // Skip drawing if we're drawing something with alpha value of 0.
- if ((col & 0xFF000000) == 0)
- return;
-
- if (rounding < 0.5f || (flags & ImDrawFlags.RoundCornersMask) == ImDrawFlags.RoundCornersMask)
- {
- // Take the fast path of drawing two triangles if no rounded corners are required.
-
- var texIdCommon = *(nint*)(drawListPtr._Data + CImGuiImDrawListSharedDataTexIdCommonOffset);
- var pushTextureId = texIdCommon != drawListPtr._CmdHeader.TextureId;
- if (pushTextureId)
- drawListPtr.PushTextureID(texIdCommon);
-
- drawListPtr.PrimReserve(6, 4);
- drawListPtr.PrimRect(min, max, col);
-
- if (pushTextureId)
- drawListPtr.PopTextureID();
- }
- else
- {
- // Defer drawing rectangle with rounded corners to path drawing operations.
- // Note that this may have a slightly different extent behaviors from the above if case.
- // This is how it is in imgui_draw.cpp.
- drawListPtr.PathRect(min, max, rounding, flags);
- drawListPtr.PathFillConvex(col);
- }
- }
-
- private void ImDrawListAddPolylineDetour(
- ImDrawListPtr drawListPtr,
- ref Vector2 points,
- int pointsCount,
- uint color,
- ImDrawFlags flags,
- float thickness)
- {
- var texIdCommon = *(nint*)(drawListPtr._Data + CImGuiImDrawListSharedDataTexIdCommonOffset);
- var pushTextureId = texIdCommon != drawListPtr._CmdHeader.TextureId;
- if (pushTextureId)
- drawListPtr.PushTextureID(texIdCommon);
-
- this.hookImDrawListAddPolyline.Original(drawListPtr, ref points, pointsCount, color, flags, thickness);
-
- if (pushTextureId)
- drawListPtr.PopTextureID();
- }
-
- private void ImDrawListAddImageRoundedDetour(ImDrawListPtr drawListPtr, nint userTextureId, ref Vector2 xy0, ref Vector2 xy1, ref Vector2 uv0, ref Vector2 uv1, uint col, float rounding, ImDrawFlags flags)
- {
- // Skip drawing if we're drawing something with alpha value of 0.
- if ((col & 0xFF000000) == 0)
- return;
-
- // Handle non-rounded cases.
- flags = FixRectCornerFlags(flags);
- if (rounding < 0.5f || (flags & ImDrawFlags.RoundCornersMask) == ImDrawFlags.RoundCornersNone)
- {
- drawListPtr.AddImage(userTextureId, xy0, xy1, uv0, uv1, col);
- return;
- }
-
- // Temporary provide the requested image as the common texture ID, so that the underlying
- // ImDrawList::AddConvexPolyFilled does not create a separate draw command and then revert back.
- // ImDrawList::AddImageRounded will temporarily push the texture ID provided by the user if the latest draw
- // command does not point to the texture we're trying to draw. Once pushed, ImDrawList::AddConvexPolyFilled
- // will leave the list of draw commands alone, so that ImGui::ShadeVertsLinearUV can safely work on the latest
- // draw command.
- ref var texIdCommon = ref *(nint*)(drawListPtr._Data + CImGuiImDrawListSharedDataTexIdCommonOffset);
- var texIdCommonPrev = texIdCommon;
- texIdCommon = userTextureId;
-
- this.hookImDrawListAddImageRounded.Original(
- drawListPtr,
- texIdCommon,
- ref xy0,
- ref xy1,
- ref uv0,
- ref uv1,
- col,
- rounding,
- flags);
-
- texIdCommon = texIdCommonPrev;
- }
-}
diff --git a/lib/cimgui b/lib/cimgui
index 7b4955bbd..a302ebabc 160000
--- a/lib/cimgui
+++ b/lib/cimgui
@@ -1 +1 @@
-Subproject commit 7b4955bbd8f7bc6c022d39503dc806fa53a6a590
+Subproject commit a302ebabcca49c2e37711ea14a0b0915d38253b0
From 2d4e4122aa77ae9e35e6cd20b8b2f37424034f6e Mon Sep 17 00:00:00 2001
From: goat
Date: Tue, 24 Dec 2024 03:57:28 +0100
Subject: [PATCH 21/88] link with static CRT
---
external/cimgui/cimgui.vcxproj | 1 +
external/cimguizmo/cimguizmo.vcxproj | 1 +
external/cimplot/cimplot.vcxproj | 1 +
3 files changed, 3 insertions(+)
diff --git a/external/cimgui/cimgui.vcxproj b/external/cimgui/cimgui.vcxproj
index c6109a131..9af4ce88d 100644
--- a/external/cimgui/cimgui.vcxproj
+++ b/external/cimgui/cimgui.vcxproj
@@ -63,6 +63,7 @@
..\..\lib\cimgui\imgui;%(AdditionalIncludeDirectories)
NotUsing
+ MultiThreaded
diff --git a/external/cimguizmo/cimguizmo.vcxproj b/external/cimguizmo/cimguizmo.vcxproj
index 56c085da3..6ff40ed36 100644
--- a/external/cimguizmo/cimguizmo.vcxproj
+++ b/external/cimguizmo/cimguizmo.vcxproj
@@ -67,6 +67,7 @@
..\..\lib\cimgui\imgui;..\..\lib\cimguizmo\ImGuizmo;..\..\lib\cimgui;%(AdditionalIncludeDirectories)
NotUsing
+ MultiThreaded
diff --git a/external/cimplot/cimplot.vcxproj b/external/cimplot/cimplot.vcxproj
index 44bcf95bb..3444ebd31 100644
--- a/external/cimplot/cimplot.vcxproj
+++ b/external/cimplot/cimplot.vcxproj
@@ -65,6 +65,7 @@
..\..\lib\cimgui\imgui;..\..\lib\cimplot\implot;..\..\lib\cimgui;%(AdditionalIncludeDirectories)
NotUsing
+ MultiThreaded
From 8773d3b873a5eef9458d65c5bb78c4b90882d7d5 Mon Sep 17 00:00:00 2001
From: goat
Date: Tue, 24 Dec 2024 16:00:09 +0100
Subject: [PATCH 22/88] fix debug build
---
external/cimgui/cimgui.vcxproj | 3 ++-
external/cimguizmo/cimguizmo.vcxproj | 3 ++-
external/cimplot/cimplot.vcxproj | 3 ++-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/external/cimgui/cimgui.vcxproj b/external/cimgui/cimgui.vcxproj
index 9af4ce88d..c8a4294dc 100644
--- a/external/cimgui/cimgui.vcxproj
+++ b/external/cimgui/cimgui.vcxproj
@@ -63,7 +63,6 @@
..\..\lib\cimgui\imgui;%(AdditionalIncludeDirectories)
NotUsing
- MultiThreaded
@@ -73,6 +72,7 @@
true
_DEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1;%(PreprocessorDefinitions)
true
+ MultiThreadedDebug
Windows
@@ -88,6 +88,7 @@
true
NDEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1;%(PreprocessorDefinitions)
true
+ MultiThreaded
Windows
diff --git a/external/cimguizmo/cimguizmo.vcxproj b/external/cimguizmo/cimguizmo.vcxproj
index 6ff40ed36..48b432327 100644
--- a/external/cimguizmo/cimguizmo.vcxproj
+++ b/external/cimguizmo/cimguizmo.vcxproj
@@ -67,7 +67,6 @@
..\..\lib\cimgui\imgui;..\..\lib\cimguizmo\ImGuizmo;..\..\lib\cimgui;%(AdditionalIncludeDirectories)
NotUsing
- MultiThreaded
@@ -77,6 +76,7 @@
true
_DEBUG;CIMGUIZMO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
+ MultiThreadedDebug
Windows
@@ -92,6 +92,7 @@
true
NDEBUG;CIMGUIZMO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
+ MultiThreaded
Windows
diff --git a/external/cimplot/cimplot.vcxproj b/external/cimplot/cimplot.vcxproj
index 3444ebd31..c7ae46a6b 100644
--- a/external/cimplot/cimplot.vcxproj
+++ b/external/cimplot/cimplot.vcxproj
@@ -65,7 +65,6 @@
..\..\lib\cimgui\imgui;..\..\lib\cimplot\implot;..\..\lib\cimgui;%(AdditionalIncludeDirectories)
NotUsing
- MultiThreaded
@@ -75,6 +74,7 @@
true
_DEBUG;CIMPLOT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
+ MultiThreadedDebug
Windows
@@ -90,6 +90,7 @@
true
NDEBUG;CIMPLOT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
+ MultiThreaded
Windows
From 12bf2f4478134fac5068679c69fb46e8829a28b1 Mon Sep 17 00:00:00 2001
From: goat
Date: Wed, 25 Dec 2024 12:46:54 +0100
Subject: [PATCH 23/88] replace nonfunctional managed asserts with proper
imgui-handled assert mechanism
---
.../Internal/DalamudConfiguration.cs | 8 +-
Dalamud/Interface/Internal/AssertHandler.cs | 177 ++++++++++++++++++
Dalamud/Interface/Internal/DalamudIme.cs | 35 ++--
.../Interface/Internal/DalamudInterface.cs | 18 +-
.../Interface/Internal/InterfaceManager.cs | 17 +-
.../ManagedAsserts/ImGuiContextOffsets.cs | 23 ---
.../ManagedAsserts/ImGuiManagedAsserts.cs | 140 --------------
.../Widgets/DevPluginsSettingsEntry.cs | 4 +
Dalamud/Interface/UiBuilder.cs | 7 -
Dalamud/Interface/Windowing/WindowSystem.cs | 6 -
external/cimgui/cimgui.vcxproj | 8 +-
lib/cimgui | 2 +-
12 files changed, 238 insertions(+), 207 deletions(-)
create mode 100644 Dalamud/Interface/Internal/AssertHandler.cs
delete mode 100644 Dalamud/Interface/Internal/ManagedAsserts/ImGuiContextOffsets.cs
delete mode 100644 Dalamud/Interface/Internal/ManagedAsserts/ImGuiManagedAsserts.cs
diff --git a/Dalamud/Configuration/Internal/DalamudConfiguration.cs b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
index 4df38d6df..3b140e9cd 100644
--- a/Dalamud/Configuration/Internal/DalamudConfiguration.cs
+++ b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
@@ -243,7 +243,7 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
///
/// Gets or sets a value indicating whether or not ImGui asserts should be enabled at startup.
///
- public bool AssertsEnabledAtStartup { get; set; }
+ public bool? ImGuiAssertsEnabledAtStartup { get; set; }
///
/// Gets or sets a value indicating whether or not docking should be globally enabled in ImGui.
@@ -605,6 +605,12 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
this.AutoUpdateBehavior ??= this.AutoUpdatePlugins
? Plugin.Internal.AutoUpdate.AutoUpdateBehavior.UpdateAll
: Plugin.Internal.AutoUpdate.AutoUpdateBehavior.OnlyNotify;
+
+ // Turn ImGui asserts on by default if we have any active dev plugins
+ if (!this.ImGuiAssertsEnabledAtStartup.HasValue && this.DevPluginLoadLocations.Any(x => x.IsEnabled))
+ {
+ this.ImGuiAssertsEnabledAtStartup = true;
+ }
#pragma warning restore CS0618
}
diff --git a/Dalamud/Interface/Internal/AssertHandler.cs b/Dalamud/Interface/Internal/AssertHandler.cs
new file mode 100644
index 000000000..22aa75b9e
--- /dev/null
+++ b/Dalamud/Interface/Internal/AssertHandler.cs
@@ -0,0 +1,177 @@
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Windows.Forms;
+
+using Dalamud.Utility;
+
+using Serilog;
+
+namespace Dalamud.Interface.Internal;
+
+///
+/// Class responsible for registering and handling ImGui asserts.
+///
+internal class AssertHandler : IDisposable
+{
+ private readonly HashSet ignoredAsserts = [];
+
+ // Store callback to avoid it from being GC'd
+ private readonly AssertCallbackDelegate callback;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public AssertHandler()
+ {
+ this.callback = (expr, file, line) => this.OnImGuiAssert(expr, file, line);
+ }
+
+ private delegate void AssertCallbackDelegate(
+ [MarshalAs(UnmanagedType.LPStr)] string expr,
+ [MarshalAs(UnmanagedType.LPStr)] string file,
+ int line);
+
+ ///
+ /// Gets or sets a value indicating whether ImGui asserts should be shown to the user.
+ ///
+ public bool ShowAsserts { get; set; } = false;
+
+ ///
+ /// Register the cimgui assert handler with the native library.
+ ///
+ public void Setup()
+ {
+ CustomNativeFunctions.igCustom_SetAssertCallback(this.callback);
+ }
+
+ ///
+ /// Unregister the cimgui assert handler with the native library.
+ ///
+ public void Shutdown()
+ {
+ CustomNativeFunctions.igCustom_SetAssertCallback(null);
+ }
+
+ ///
+ public void Dispose()
+ {
+ this.Shutdown();
+ }
+
+ private void OnImGuiAssert(string expr, string file, int line)
+ {
+ Log.Warning("ImGui assertion failed: {Expr} at {File}:{Line}", expr, file, line);
+
+ if (!this.ShowAsserts)
+ return;
+
+ var key = $"{file}:{line}";
+ if (this.ignoredAsserts.Contains(key))
+ return;
+
+ // TODO: It would be nice to get unmanaged stack frames here, seems hard though without pulling that
+ // entire code in from the crash handler
+ var originalStackTrace = new StackTrace(2).ToString();
+
+ string? GetRepoUrl()
+ {
+ // TODO: implot, imguizmo?
+ const string userName = "goatcorp";
+ const string repoName = "gc-imgui";
+ const string branch = "1.88-enhanced-abifix";
+
+ if (!file.Contains("imgui", StringComparison.OrdinalIgnoreCase))
+ return null;
+
+ var lastSlash = file.LastIndexOf('\\');
+ var fileName = file[(lastSlash + 1)..];
+ return $"https://github.com/{userName}/{repoName}/blob/{branch}/{fileName}#L{line}";
+ }
+
+ var gitHubUrl = GetRepoUrl();
+ var showOnGitHubButton = new TaskDialogButton
+ {
+ Text = "Show on GitHub",
+ AllowCloseDialog = false,
+ Enabled = !gitHubUrl.IsNullOrEmpty(),
+ };
+ showOnGitHubButton.Click += (_, _) =>
+ {
+ if (!gitHubUrl.IsNullOrEmpty())
+ Util.OpenLink(gitHubUrl);
+ };
+
+ var breakButton = new TaskDialogButton
+ {
+ Text = "Break",
+ AllowCloseDialog = true,
+ };
+
+ var ignoreButton = TaskDialogButton.Ignore;
+ var abortButton = TaskDialogButton.Abort;
+
+ TaskDialogButton? result = null;
+ void DialogThreadStart()
+ {
+ // TODO(goat): This is probably not gonna work if we showed the loading dialog
+ // this session since it already loaded visual styles...
+ Application.EnableVisualStyles();
+
+ var page = new TaskDialogPage()
+ {
+ Heading = "ImGui assertion failed",
+ Caption = "Dalamud",
+ Expander = new TaskDialogExpander
+ {
+ CollapsedButtonText = "Show stack trace",
+ ExpandedButtonText = "Hide stack trace",
+ Text = originalStackTrace,
+ },
+ Text = $"Some code in a plugin or Dalamud itself has caused an internal assertion in ImGui to fail. The game will most likely crash now.\n\n{expr}\nAt: {file}:{line}",
+ Icon = TaskDialogIcon.Warning,
+ Buttons =
+ [
+ showOnGitHubButton,
+ breakButton,
+ ignoreButton,
+ abortButton,
+ ],
+ DefaultButton = showOnGitHubButton,
+ };
+
+ result = TaskDialog.ShowDialog(page);
+ }
+
+ // Run in a separate thread because of STA and to not mess up other stuff
+ var thread = new Thread(DialogThreadStart)
+ {
+ Name = "Dalamud ImGui Assert Dialog",
+ };
+ thread.SetApartmentState(ApartmentState.STA);
+ thread.Start();
+ thread.Join();
+
+ if (result == breakButton)
+ {
+ Debugger.Break();
+ }
+ else if (result == abortButton)
+ {
+ Environment.Exit(-1);
+ }
+ else if (result == ignoreButton)
+ {
+ this.ignoredAsserts.Add(key);
+ }
+ }
+
+ private static class CustomNativeFunctions
+ {
+ [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)]
+#pragma warning disable SA1300
+ public static extern void igCustom_SetAssertCallback(AssertCallbackDelegate callback);
+#pragma warning restore SA1300
+ }
+}
diff --git a/Dalamud/Interface/Internal/DalamudIme.cs b/Dalamud/Interface/Internal/DalamudIme.cs
index c061ec12d..7beb5e58b 100644
--- a/Dalamud/Interface/Internal/DalamudIme.cs
+++ b/Dalamud/Interface/Internal/DalamudIme.cs
@@ -16,7 +16,6 @@ using Dalamud.Game.Text;
using Dalamud.Hooking.WndProcHook;
using Dalamud.Interface.Colors;
using Dalamud.Interface.GameFonts;
-using Dalamud.Interface.Internal.ManagedAsserts;
using Dalamud.Interface.ManagedFontAtlas.Internals;
using Dalamud.Interface.Utility;
@@ -185,7 +184,7 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
return true;
if (!ImGui.GetIO().ConfigInputTextCursorBlink)
return true;
- var textState = TextState;
+ var textState = CustomNativeFunctions.igCustom_GetInputTextState();
if (textState->Id == 0 || (textState->Flags & ImGuiInputTextFlags.ReadOnly) != 0)
return true;
if (textState->CursorAnim <= 0)
@@ -194,9 +193,6 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
}
}
- private static ImGuiInputTextState* TextState =>
- (ImGuiInputTextState*)(ImGui.GetCurrentContext() + ImGuiContextOffsets.TextStateOffset);
-
/// Gets a value indicating whether to display partial conversion status.
private bool ShowPartialConversion => this.partialConversionFrom != 0 ||
this.partialConversionTo != this.compositionString.Length;
@@ -341,7 +337,8 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
try
{
- var invalidTarget = TextState->Id == 0 || (TextState->Flags & ImGuiInputTextFlags.ReadOnly) != 0;
+ var textState = CustomNativeFunctions.igCustom_GetInputTextState();
+ var invalidTarget = textState->Id == 0 || (textState->Flags & ImGuiInputTextFlags.ReadOnly) != 0;
#if IMEDEBUG
switch (args.Message)
@@ -570,19 +567,20 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
this.ReflectCharacterEncounters(newString);
+ var textState = CustomNativeFunctions.igCustom_GetInputTextState();
if (this.temporaryUndoSelection is not null)
{
- TextState->Undo();
- TextState->SelectionTuple = this.temporaryUndoSelection.Value;
+ textState->Undo();
+ textState->SelectionTuple = this.temporaryUndoSelection.Value;
this.temporaryUndoSelection = null;
}
- TextState->SanitizeSelectionRange();
- if (TextState->ReplaceSelectionAndPushUndo(newString))
- this.temporaryUndoSelection = TextState->SelectionTuple;
+ textState->SanitizeSelectionRange();
+ if (textState->ReplaceSelectionAndPushUndo(newString))
+ this.temporaryUndoSelection = textState->SelectionTuple;
// Put the cursor at the beginning, so that the candidate window appears aligned with the text.
- TextState->SetSelectionRange(TextState->SelectionTuple.Start, newString.Length, 0);
+ textState->SetSelectionRange(textState->SelectionTuple.Start, newString.Length, 0);
if (finalCommit)
{
@@ -627,7 +625,10 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
this.partialConversionFrom = this.partialConversionTo = 0;
this.compositionCursorOffset = 0;
this.temporaryUndoSelection = null;
- TextState->Stb.SelectStart = TextState->Stb.Cursor = TextState->Stb.SelectEnd;
+
+ var textState = CustomNativeFunctions.igCustom_GetInputTextState();
+ textState->Stb.SelectStart = textState->Stb.Cursor = textState->Stb.SelectEnd;
+
this.candidateStrings.Clear();
this.immCandNative = default;
if (invokeCancel)
@@ -1113,6 +1114,14 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
}
}
+ private static class CustomNativeFunctions
+ {
+ [DllImport("cimgui")]
+#pragma warning disable SA1300
+ public static extern ImGuiInputTextState* igCustom_GetInputTextState();
+#pragma warning restore SA1300
+ }
+
#if IMEDEBUG
private static class ImeDebug
{
diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs
index a21cf2070..0aa10f514 100644
--- a/Dalamud/Interface/Internal/DalamudInterface.cs
+++ b/Dalamud/Interface/Internal/DalamudInterface.cs
@@ -18,7 +18,6 @@ using Dalamud.Game.Internal;
using Dalamud.Hooking;
using Dalamud.Interface.Animation.EasingFunctions;
using Dalamud.Interface.Colors;
-using Dalamud.Interface.Internal.ManagedAsserts;
using Dalamud.Interface.Internal.Windows;
using Dalamud.Interface.Internal.Windows.Data;
using Dalamud.Interface.Internal.Windows.PluginInstaller;
@@ -163,7 +162,7 @@ internal class DalamudInterface : IInternalDisposableService
this.WindowSystem.AddWindow(this.branchSwitcherWindow);
this.WindowSystem.AddWindow(this.hitchSettingsWindow);
- ImGuiManagedAsserts.AssertsEnabled = configuration.AssertsEnabledAtStartup;
+ this.interfaceManager.ShowAsserts = configuration.ImGuiAssertsEnabledAtStartup ?? false;
this.isImGuiDrawDevMenu = this.isImGuiDrawDevMenu || configuration.DevBarOpenAtStartup;
this.interfaceManager.Draw += this.OnDraw;
@@ -832,6 +831,12 @@ internal class DalamudInterface : IInternalDisposableService
hook.Enable();
}
}
+
+ if (ImGui.MenuItem("Cause ImGui assert"))
+ {
+ ImGui.PopStyleVar();
+ ImGui.PopStyleVar();
+ }
ImGui.EndMenu();
}
@@ -865,15 +870,16 @@ internal class DalamudInterface : IInternalDisposableService
ImGui.Separator();
- var val = ImGuiManagedAsserts.AssertsEnabled;
+ var val = this.interfaceManager.ShowAsserts;
if (ImGui.MenuItem("Enable Asserts", string.Empty, ref val))
{
- ImGuiManagedAsserts.AssertsEnabled = val;
+ this.interfaceManager.ShowAsserts = val;
}
- if (ImGui.MenuItem("Enable asserts at startup", null, this.configuration.AssertsEnabledAtStartup))
+ var assertsEnabled = this.configuration.ImGuiAssertsEnabledAtStartup ?? false;
+ if (ImGui.MenuItem("Enable asserts at startup", null, assertsEnabled))
{
- this.configuration.AssertsEnabledAtStartup = !this.configuration.AssertsEnabledAtStartup;
+ this.configuration.ImGuiAssertsEnabledAtStartup = !assertsEnabled;
this.configuration.QueueSave();
}
diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs
index f532b0412..af9f61647 100644
--- a/Dalamud/Interface/Internal/InterfaceManager.cs
+++ b/Dalamud/Interface/Internal/InterfaceManager.cs
@@ -20,7 +20,6 @@ using Dalamud.Hooking.WndProcHook;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal.DesignSystem;
-using Dalamud.Interface.Internal.ManagedAsserts;
using Dalamud.Interface.Internal.ReShadeHandling;
using Dalamud.Interface.ManagedFontAtlas;
using Dalamud.Interface.ManagedFontAtlas.Internals;
@@ -93,6 +92,8 @@ internal partial class InterfaceManager : IInternalDisposableService
private readonly ConcurrentQueue runBeforeImGuiRender = new();
private readonly ConcurrentQueue runAfterImGuiRender = new();
+
+ private readonly AssertHandler assertHandler = new();
private RawDX11Scene? scene;
@@ -267,11 +268,20 @@ internal partial class InterfaceManager : IInternalDisposableService
///
public long CumulativePresentCalls { get; private set; }
+ ///
+ public bool ShowAsserts
+ {
+ get => this.assertHandler.ShowAsserts;
+ set => this.assertHandler.ShowAsserts = value;
+ }
+
///
/// Dispose of managed and unmanaged resources.
///
void IInternalDisposableService.DisposeService()
{
+ this.assertHandler.Dispose();
+
// Unload hooks from the framework thread if possible.
// We're currently off the framework thread, as this function can only be called from
// ServiceManager.UnloadAllServices, which is called from EntryPoint.RunThread.
@@ -565,6 +575,7 @@ internal partial class InterfaceManager : IInternalDisposableService
{
try
{
+ this.assertHandler.Setup();
newScene = new RawDX11Scene((nint)swapChain);
}
catch (DllNotFoundException ex)
@@ -1128,15 +1139,11 @@ internal partial class InterfaceManager : IInternalDisposableService
WindowSystem.HasAnyWindowSystemFocus = false;
WindowSystem.FocusedWindowSystemNamespace = string.Empty;
- var snap = ImGuiManagedAsserts.GetSnapshot();
-
if (this.IsDispatchingEvents)
{
this.Draw?.Invoke();
Service.GetNullable()?.Draw();
}
-
- ImGuiManagedAsserts.ReportProblems("Dalamud Core", snap);
}
///
diff --git a/Dalamud/Interface/Internal/ManagedAsserts/ImGuiContextOffsets.cs b/Dalamud/Interface/Internal/ManagedAsserts/ImGuiContextOffsets.cs
deleted file mode 100644
index 89e23ab78..000000000
--- a/Dalamud/Interface/Internal/ManagedAsserts/ImGuiContextOffsets.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-namespace Dalamud.Interface.Internal.ManagedAsserts;
-
-///
-/// Offsets to various data in ImGui context.
-///
-///
-/// Last updated for ImGui 1.83.
-///
-[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Document the unsage instead.")]
-internal static class ImGuiContextOffsets
-{
- public const int CurrentWindowStackOffset = 0x73A;
-
- public const int ColorStackOffset = 0x79C;
-
- public const int StyleVarStackOffset = 0x7A0;
-
- public const int FontStackOffset = 0x7A4;
-
- public const int BeginPopupStackOffset = 0x7B8;
-
- public const int TextStateOffset = 0x4588;
-}
diff --git a/Dalamud/Interface/Internal/ManagedAsserts/ImGuiManagedAsserts.cs b/Dalamud/Interface/Internal/ManagedAsserts/ImGuiManagedAsserts.cs
deleted file mode 100644
index ff42e93f3..000000000
--- a/Dalamud/Interface/Internal/ManagedAsserts/ImGuiManagedAsserts.cs
+++ /dev/null
@@ -1,140 +0,0 @@
-using System.Diagnostics;
-
-using ImGuiNET;
-
-using static Dalamud.NativeFunctions;
-
-namespace Dalamud.Interface.Internal.ManagedAsserts;
-
-///
-/// Report ImGui problems with a MessageBox dialog.
-///
-internal static class ImGuiManagedAsserts
-{
- ///
- /// Gets or sets a value indicating whether asserts are enabled for ImGui.
- ///
- public static bool AssertsEnabled { get; set; }
-
- ///
- /// Create a snapshot of the current ImGui context.
- /// Should be called before rendering an ImGui frame.
- ///
- /// A snapshot of the current context.
- public static unsafe ImGuiContextSnapshot GetSnapshot()
- {
- var contextPtr = ImGui.GetCurrentContext();
-
- var styleVarStack = *((int*)contextPtr + ImGuiContextOffsets.StyleVarStackOffset); // ImVector.Size
- var colorStack = *((int*)contextPtr + ImGuiContextOffsets.ColorStackOffset); // ImVector.Size
- var fontStack = *((int*)contextPtr + ImGuiContextOffsets.FontStackOffset); // ImVector.Size
- var popupStack = *((int*)contextPtr + ImGuiContextOffsets.BeginPopupStackOffset); // ImVector.Size
- var windowStack = *((int*)contextPtr + ImGuiContextOffsets.CurrentWindowStackOffset); // ImVector.Size
-
- return new ImGuiContextSnapshot
- {
- StyleVarStackSize = styleVarStack,
- ColorStackSize = colorStack,
- FontStackSize = fontStack,
- BeginPopupStackSize = popupStack,
- WindowStackSize = windowStack,
- };
- }
-
- ///
- /// Compare a snapshot to the current post-draw state and report any errors in a MessageBox dialog.
- ///
- /// The source of any problems, something to blame.
- /// ImGui context snapshot.
- public static void ReportProblems(string source, ImGuiContextSnapshot before)
- {
- // TODO: Needs to be updated for ImGui 1.88
- return;
-
-#pragma warning disable CS0162
- if (!AssertsEnabled)
- {
- return;
- }
-
- var cSnap = GetSnapshot();
-
- if (before.StyleVarStackSize != cSnap.StyleVarStackSize)
- {
- ShowAssert(source, $"You forgot to pop a style var!\n\nBefore: {before.StyleVarStackSize}, after: {cSnap.StyleVarStackSize}");
- return;
- }
-
- if (before.ColorStackSize != cSnap.ColorStackSize)
- {
- ShowAssert(source, $"You forgot to pop a color!\n\nBefore: {before.ColorStackSize}, after: {cSnap.ColorStackSize}");
- return;
- }
-
- if (before.FontStackSize != cSnap.FontStackSize)
- {
- ShowAssert(source, $"You forgot to pop a font!\n\nBefore: {before.FontStackSize}, after: {cSnap.FontStackSize}");
- return;
- }
-
- if (before.BeginPopupStackSize != cSnap.BeginPopupStackSize)
- {
- ShowAssert(source, $"You forgot to end a popup!\n\nBefore: {before.BeginPopupStackSize}, after: {cSnap.BeginPopupStackSize}");
- return;
- }
-
- if (cSnap.WindowStackSize != 1)
- {
- if (cSnap.WindowStackSize > 1)
- {
- ShowAssert(source, $"Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?\n\ncSnap.WindowStackSize = {cSnap.WindowStackSize}");
- }
- else
- {
- ShowAssert(source, $"Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?\n\ncSnap.WindowStackSize = {cSnap.WindowStackSize}");
- }
- }
-#pragma warning restore CS0162
- }
-
- private static void ShowAssert(string source, string message)
- {
- var caption = $"You fucked up";
- message = $"{message}\n\nSource: {source}\n\nAsserts are now disabled. You may re-enable them.";
- var flags = MessageBoxType.Ok | MessageBoxType.IconError;
-
- _ = MessageBoxW(Process.GetCurrentProcess().MainWindowHandle, message, caption, flags);
- AssertsEnabled = false;
- }
-
- ///
- /// A snapshot of various ImGui context properties.
- ///
- public class ImGuiContextSnapshot
- {
- ///
- /// Gets the ImGui style var stack size.
- ///
- public int StyleVarStackSize { get; init; }
-
- ///
- /// Gets the ImGui color stack size.
- ///
- public int ColorStackSize { get; init; }
-
- ///
- /// Gets the ImGui font stack size.
- ///
- public int FontStackSize { get; init; }
-
- ///
- /// Gets the ImGui begin popup stack size.
- ///
- public int BeginPopupStackSize { get; init; }
-
- ///
- /// Gets the ImGui window stack size.
- ///
- public int WindowStackSize { get; init; }
- }
-}
diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs
index fe4462ce2..101b21d38 100644
--- a/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs
+++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs
@@ -222,6 +222,10 @@ public class DevPluginsSettingsEntry : SettingsEntry
this.devPluginLocationsChanged = true;
this.devPluginTempLocation = string.Empty;
}
+
+ var config = Service.Get();
+ if (!config.ImGuiAssertsEnabledAtStartup.HasValue)
+ config.ImGuiAssertsEnabledAtStartup = true;
}
public override void PostDraw()
diff --git a/Dalamud/Interface/UiBuilder.cs b/Dalamud/Interface/UiBuilder.cs
index 1413f3347..2fc8c83b1 100644
--- a/Dalamud/Interface/UiBuilder.cs
+++ b/Dalamud/Interface/UiBuilder.cs
@@ -9,7 +9,6 @@ using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.Gui;
using Dalamud.Interface.FontIdentifier;
using Dalamud.Interface.Internal;
-using Dalamud.Interface.Internal.ManagedAsserts;
using Dalamud.Interface.ManagedFontAtlas;
using Dalamud.Interface.ManagedFontAtlas.Internals;
using Dalamud.Plugin.Internal.Types;
@@ -713,8 +712,6 @@ public sealed class UiBuilder : IDisposable, IUiBuilder
ImGui.End();
}
- var snapshot = this.Draw is null ? null : ImGuiManagedAsserts.GetSnapshot();
-
try
{
this.Draw?.InvokeSafely();
@@ -728,10 +725,6 @@ public sealed class UiBuilder : IDisposable, IUiBuilder
this.hasErrorWindow = true;
}
- // Only if Draw was successful
- if (this.Draw is not null && snapshot is not null)
- ImGuiManagedAsserts.ReportProblems(this.namespaceName, snapshot);
-
this.FrameCount++;
if (DoStats)
diff --git a/Dalamud/Interface/Windowing/WindowSystem.cs b/Dalamud/Interface/Windowing/WindowSystem.cs
index dc4d6aca1..a3eab2a60 100644
--- a/Dalamud/Interface/Windowing/WindowSystem.cs
+++ b/Dalamud/Interface/Windowing/WindowSystem.cs
@@ -2,7 +2,6 @@ using System.Collections.Generic;
using System.Linq;
using Dalamud.Configuration.Internal;
-using Dalamud.Interface.Internal.ManagedAsserts;
using ImGuiNET;
using Serilog;
@@ -112,12 +111,7 @@ public class WindowSystem
#if DEBUG
// Log.Verbose($"[WS{(hasNamespace ? "/" + this.Namespace : string.Empty)}] Drawing {window.WindowName}");
#endif
- var snapshot = ImGuiManagedAsserts.GetSnapshot();
-
window.DrawInternal(config);
-
- var source = ($"{this.Namespace}::" ?? string.Empty) + window.WindowName;
- ImGuiManagedAsserts.ReportProblems(source, snapshot);
}
var focusedWindow = this.windows.FirstOrDefault(window => window.IsFocused && window.RespectCloseHotkey);
diff --git a/external/cimgui/cimgui.vcxproj b/external/cimgui/cimgui.vcxproj
index c8a4294dc..a7a7ddb0e 100644
--- a/external/cimgui/cimgui.vcxproj
+++ b/external/cimgui/cimgui.vcxproj
@@ -58,19 +58,17 @@
..\$(Platform)\$(Configuration)\
-
- ..\..\lib\cimgui\imgui;%(AdditionalIncludeDirectories)
+ ..\..\lib\cimgui\imgui;..\..\lib\cimgui;%(AdditionalIncludeDirectories)
NotUsing
-
Level3
true
- _DEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1;%(PreprocessorDefinitions)
+ _DEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1;IMGUI_USER_CONFIG="cimgui_user.h";%(PreprocessorDefinitions)
true
MultiThreadedDebug
@@ -86,7 +84,7 @@
true
true
true
- NDEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1;%(PreprocessorDefinitions)
+ NDEBUG;CIMGUI_EXPORTS;_WINDOWS;_USRDLL;IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1;IMGUI_USER_CONFIG="cimgui_user.h";%(PreprocessorDefinitions)
true
MultiThreaded
diff --git a/lib/cimgui b/lib/cimgui
index a302ebabc..fd2377934 160000
--- a/lib/cimgui
+++ b/lib/cimgui
@@ -1 +1 @@
-Subproject commit a302ebabcca49c2e37711ea14a0b0915d38253b0
+Subproject commit fd2377934f2cc007982e21ab82e54b41955cb658
From 9d8bcb7a24148a33f2a8d182d73a4baf243e91a1 Mon Sep 17 00:00:00 2001
From: goat
Date: Wed, 25 Dec 2024 17:03:22 +0100
Subject: [PATCH 24/88] add "disable for this session" button to ImGui asserts
---
.../Internal/{ => Asserts}/AssertHandler.cs | 23 +++++++++++--------
.../Interface/Internal/InterfaceManager.cs | 1 +
2 files changed, 15 insertions(+), 9 deletions(-)
rename Dalamud/Interface/Internal/{ => Asserts}/AssertHandler.cs (91%)
diff --git a/Dalamud/Interface/Internal/AssertHandler.cs b/Dalamud/Interface/Internal/Asserts/AssertHandler.cs
similarity index 91%
rename from Dalamud/Interface/Internal/AssertHandler.cs
rename to Dalamud/Interface/Internal/Asserts/AssertHandler.cs
index 22aa75b9e..b0cfb462c 100644
--- a/Dalamud/Interface/Internal/AssertHandler.cs
+++ b/Dalamud/Interface/Internal/Asserts/AssertHandler.cs
@@ -8,7 +8,7 @@ using Dalamud.Utility;
using Serilog;
-namespace Dalamud.Interface.Internal;
+namespace Dalamud.Interface.Internal.Asserts;
///
/// Class responsible for registering and handling ImGui asserts.
@@ -36,7 +36,7 @@ internal class AssertHandler : IDisposable
///
/// Gets or sets a value indicating whether ImGui asserts should be shown to the user.
///
- public bool ShowAsserts { get; set; } = false;
+ public bool ShowAsserts { get; set; }
///
/// Register the cimgui assert handler with the native library.
@@ -93,7 +93,7 @@ internal class AssertHandler : IDisposable
var gitHubUrl = GetRepoUrl();
var showOnGitHubButton = new TaskDialogButton
{
- Text = "Show on GitHub",
+ Text = "Open GitHub",
AllowCloseDialog = false,
Enabled = !gitHubUrl.IsNullOrEmpty(),
};
@@ -108,9 +108,14 @@ internal class AssertHandler : IDisposable
Text = "Break",
AllowCloseDialog = true,
};
+
+ var disableButton = new TaskDialogButton
+ {
+ Text = "Disable for this session",
+ AllowCloseDialog = true,
+ };
var ignoreButton = TaskDialogButton.Ignore;
- var abortButton = TaskDialogButton.Abort;
TaskDialogButton? result = null;
void DialogThreadStart()
@@ -119,7 +124,7 @@ internal class AssertHandler : IDisposable
// this session since it already loaded visual styles...
Application.EnableVisualStyles();
- var page = new TaskDialogPage()
+ var page = new TaskDialogPage
{
Heading = "ImGui assertion failed",
Caption = "Dalamud",
@@ -135,8 +140,8 @@ internal class AssertHandler : IDisposable
[
showOnGitHubButton,
breakButton,
+ disableButton,
ignoreButton,
- abortButton,
],
DefaultButton = showOnGitHubButton,
};
@@ -157,9 +162,9 @@ internal class AssertHandler : IDisposable
{
Debugger.Break();
}
- else if (result == abortButton)
+ else if (result == disableButton)
{
- Environment.Exit(-1);
+ this.ShowAsserts = false;
}
else if (result == ignoreButton)
{
@@ -171,7 +176,7 @@ internal class AssertHandler : IDisposable
{
[DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)]
#pragma warning disable SA1300
- public static extern void igCustom_SetAssertCallback(AssertCallbackDelegate callback);
+ public static extern void igCustom_SetAssertCallback(AssertCallbackDelegate? callback);
#pragma warning restore SA1300
}
}
diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs
index af9f61647..36f48f9b8 100644
--- a/Dalamud/Interface/Internal/InterfaceManager.cs
+++ b/Dalamud/Interface/Internal/InterfaceManager.cs
@@ -19,6 +19,7 @@ using Dalamud.Hooking.Internal;
using Dalamud.Hooking.WndProcHook;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.ImGuiNotification.Internal;
+using Dalamud.Interface.Internal.Asserts;
using Dalamud.Interface.Internal.DesignSystem;
using Dalamud.Interface.Internal.ReShadeHandling;
using Dalamud.Interface.ManagedFontAtlas;
From 8b06ae3f006b8f392c29de1a2cc61f57c66b3f37 Mon Sep 17 00:00:00 2001
From: goat
Date: Wed, 25 Dec 2024 17:04:35 +0100
Subject: [PATCH 25/88] add ImGui assert options to experimental tab
---
.../Settings/Tabs/SettingsTabExperimental.cs | 20 +++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs
index aef674ac4..4354daffe 100644
--- a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs
+++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs
@@ -65,6 +65,26 @@ public class SettingsTabExperimental : SettingsTab
new GapSettingsEntry(5, true),
new DevPluginsSettingsEntry(),
+
+ new SettingsEntry(
+ Loc.Localize(
+ "DalamudSettingEnableImGuiAsserts",
+ "Enable ImGui asserts"),
+ Loc.Localize(
+ "DalamudSettingEnableImGuiAssertsHint",
+ "If this setting is enabled, a window containing further details will be shown when an internal assertion in ImGui fails.\nWe recommend enabling this when developing plugins."),
+ c => Service.Get().ShowAsserts,
+ (v, _) => Service.Get().ShowAsserts = v),
+
+ new SettingsEntry(
+ Loc.Localize(
+ "DalamudSettingEnableImGuiAssertsAtStartup",
+ "Always enable ImGui asserts at startup"),
+ Loc.Localize(
+ "DalamudSettingEnableImGuiAssertsAtStartupHint",
+ "This will enable ImGui asserts every time the game starts."),
+ c => c.ImGuiAssertsEnabledAtStartup ?? false,
+ (v, c) => c.ImGuiAssertsEnabledAtStartup = v),
new GapSettingsEntry(5, true),
From 108308170638753feb4e8d06811612ed5bfbfd07 Mon Sep 17 00:00:00 2001
From: KazWolfe
Date: Wed, 25 Dec 2024 14:33:23 -0800
Subject: [PATCH 26/88] fix: Safely invoke marketboard events being sent to
plugins. (#2150)
---
Dalamud/Game/Marketboard/MarketBoard.cs | 117 ++++++++++++++++++++----
1 file changed, 100 insertions(+), 17 deletions(-)
diff --git a/Dalamud/Game/Marketboard/MarketBoard.cs b/Dalamud/Game/Marketboard/MarketBoard.cs
index 3642b86b8..79de09dea 100644
--- a/Dalamud/Game/Marketboard/MarketBoard.cs
+++ b/Dalamud/Game/Marketboard/MarketBoard.cs
@@ -1,9 +1,15 @@
-using Dalamud.Game.Network.Internal;
+using System.Linq;
+
+using Dalamud.Game.Network.Internal;
using Dalamud.Game.Network.Structures;
using Dalamud.IoC;
using Dalamud.IoC.Internal;
+using Dalamud.Logging.Internal;
+using Dalamud.Plugin.Internal.Types;
using Dalamud.Plugin.Services;
+using static Dalamud.Plugin.Services.IMarketBoard;
+
namespace Dalamud.Game.MarketBoard;
///
@@ -29,19 +35,19 @@ internal class MarketBoard : IInternalDisposableService, IMarketBoard
}
///
- public event IMarketBoard.HistoryReceivedDelegate? HistoryReceived;
+ public event HistoryReceivedDelegate? HistoryReceived;
///
- public event IMarketBoard.ItemPurchasedDelegate? ItemPurchased;
+ public event ItemPurchasedDelegate? ItemPurchased;
///
- public event IMarketBoard.OfferingsReceivedDelegate? OfferingsReceived;
+ public event OfferingsReceivedDelegate? OfferingsReceived;
///
- public event IMarketBoard.PurchaseRequestedDelegate? PurchaseRequested;
+ public event PurchaseRequestedDelegate? PurchaseRequested;
///
- public event IMarketBoard.TaxRatesReceivedDelegate? TaxRatesReceived;
+ public event TaxRatesReceivedDelegate? TaxRatesReceived;
///
public void DisposeService()
@@ -89,35 +95,42 @@ internal class MarketBoard : IInternalDisposableService, IMarketBoard
#pragma warning restore SA1015
internal class MarketBoardPluginScoped : IInternalDisposableService, IMarketBoard
{
+ private static readonly ModuleLog Log = new(nameof(MarketBoardPluginScoped));
+
[ServiceManager.ServiceDependency]
private readonly MarketBoard marketBoardService = Service.Get();
+ private readonly string owningPluginName;
+
///
/// Initializes a new instance of the class.
///
- internal MarketBoardPluginScoped()
+ /// The plugin owning this service.
+ internal MarketBoardPluginScoped(LocalPlugin? plugin)
{
this.marketBoardService.HistoryReceived += this.OnHistoryReceived;
this.marketBoardService.ItemPurchased += this.OnItemPurchased;
this.marketBoardService.OfferingsReceived += this.OnOfferingsReceived;
this.marketBoardService.PurchaseRequested += this.OnPurchaseRequested;
this.marketBoardService.TaxRatesReceived += this.OnTaxRatesReceived;
+
+ this.owningPluginName = plugin?.InternalName ?? "DalamudInternal";
}
///
- public event IMarketBoard.HistoryReceivedDelegate? HistoryReceived;
+ public event HistoryReceivedDelegate? HistoryReceived;
///
- public event IMarketBoard.ItemPurchasedDelegate? ItemPurchased;
+ public event ItemPurchasedDelegate? ItemPurchased;
///
- public event IMarketBoard.OfferingsReceivedDelegate? OfferingsReceived;
+ public event OfferingsReceivedDelegate? OfferingsReceived;
///
- public event IMarketBoard.PurchaseRequestedDelegate? PurchaseRequested;
+ public event PurchaseRequestedDelegate? PurchaseRequested;
///
- public event IMarketBoard.TaxRatesReceivedDelegate? TaxRatesReceived;
+ public event TaxRatesReceivedDelegate? TaxRatesReceived;
///
void IInternalDisposableService.DisposeService()
@@ -137,26 +150,96 @@ internal class MarketBoardPluginScoped : IInternalDisposableService, IMarketBoar
private void OnHistoryReceived(IMarketBoardHistory history)
{
- this.HistoryReceived?.Invoke(history);
+ if (this.HistoryReceived == null) return;
+
+ foreach (var action in this.HistoryReceived.GetInvocationList().Cast())
+ {
+ try
+ {
+ action.Invoke(history);
+ }
+ catch (Exception ex)
+ {
+ this.LogInvocationError(ex, nameof(this.HistoryReceived));
+ }
+ }
}
private void OnItemPurchased(IMarketBoardPurchase purchase)
{
- this.ItemPurchased?.Invoke(purchase);
+ if (this.ItemPurchased == null) return;
+
+ foreach (var action in this.ItemPurchased.GetInvocationList().Cast())
+ {
+ try
+ {
+ action.Invoke(purchase);
+ }
+ catch (Exception ex)
+ {
+ this.LogInvocationError(ex, nameof(this.ItemPurchased));
+ }
+ }
}
private void OnOfferingsReceived(IMarketBoardCurrentOfferings currentOfferings)
{
- this.OfferingsReceived?.Invoke(currentOfferings);
+ if (this.OfferingsReceived == null) return;
+
+ foreach (var action in this.OfferingsReceived.GetInvocationList()
+ .Cast())
+ {
+ try
+ {
+ action.Invoke(currentOfferings);
+ }
+ catch (Exception ex)
+ {
+ this.LogInvocationError(ex, nameof(this.OfferingsReceived));
+ }
+ }
}
private void OnPurchaseRequested(IMarketBoardPurchaseHandler purchaseHandler)
{
- this.PurchaseRequested?.Invoke(purchaseHandler);
+ if (this.PurchaseRequested == null) return;
+
+ foreach (var action in this.PurchaseRequested.GetInvocationList().Cast())
+ {
+ try
+ {
+ action.Invoke(purchaseHandler);
+ }
+ catch (Exception ex)
+ {
+ this.LogInvocationError(ex, nameof(this.PurchaseRequested));
+ }
+ }
}
private void OnTaxRatesReceived(IMarketTaxRates taxRates)
{
- this.TaxRatesReceived?.Invoke(taxRates);
+ if (this.TaxRatesReceived == null) return;
+
+ foreach (var action in this.TaxRatesReceived.GetInvocationList().Cast())
+ {
+ try
+ {
+ action.Invoke(taxRates);
+ }
+ catch (Exception ex)
+ {
+ this.LogInvocationError(ex, nameof(this.TaxRatesReceived));
+ }
+ }
+ }
+
+ private void LogInvocationError(Exception ex, string delegateName)
+ {
+ Log.Error(
+ ex,
+ "An error occured while invoking event `{evName}` for {plugin}",
+ delegateName,
+ this.owningPluginName);
}
}
From b79c646b9ba5dfb31677a3d8ae1085c16979bc6f Mon Sep 17 00:00:00 2001
From: goat
Date: Wed, 25 Dec 2024 23:42:50 +0100
Subject: [PATCH 27/88] only turn ImGui asserts on if we are actually loading a
devplugin
---
Dalamud/Configuration/Internal/DalamudConfiguration.cs | 6 ------
Dalamud/Plugin/Internal/PluginManager.cs | 3 +++
2 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/Dalamud/Configuration/Internal/DalamudConfiguration.cs b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
index 3b140e9cd..22fb2f448 100644
--- a/Dalamud/Configuration/Internal/DalamudConfiguration.cs
+++ b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
@@ -605,12 +605,6 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
this.AutoUpdateBehavior ??= this.AutoUpdatePlugins
? Plugin.Internal.AutoUpdate.AutoUpdateBehavior.UpdateAll
: Plugin.Internal.AutoUpdate.AutoUpdateBehavior.OnlyNotify;
-
- // Turn ImGui asserts on by default if we have any active dev plugins
- if (!this.ImGuiAssertsEnabledAtStartup.HasValue && this.DevPluginLoadLocations.Any(x => x.IsEnabled))
- {
- this.ImGuiAssertsEnabledAtStartup = true;
- }
#pragma warning restore CS0618
}
diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs
index 9d71c60df..45a923aed 100644
--- a/Dalamud/Plugin/Internal/PluginManager.cs
+++ b/Dalamud/Plugin/Internal/PluginManager.cs
@@ -1572,6 +1572,9 @@ internal class PluginManager : IInternalDisposableService
{
Log.Information($"Loading dev plugin {name}");
plugin = new LocalDevPlugin(dllFile, manifest);
+
+ // This is a dev plugin - turn ImGui asserts on by default if we haven't chosen yet
+ this.configuration.ImGuiAssertsEnabledAtStartup ??= true;
}
else
{
From 776a838dbeb15a8002d33b637a136ffbeeb330b7 Mon Sep 17 00:00:00 2001
From: goat
Date: Wed, 25 Dec 2024 23:47:18 +0100
Subject: [PATCH 28/88] remove legacy MonoMod patches for codebase and assembly
location
---
Dalamud/Plugin/Internal/PluginManager.cs | 125 -------------------
Dalamud/Plugin/Internal/Types/LocalPlugin.cs | 4 -
2 files changed, 129 deletions(-)
diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs
index 45a923aed..b70b74b03 100644
--- a/Dalamud/Plugin/Internal/PluginManager.cs
+++ b/Dalamud/Plugin/Internal/PluginManager.cs
@@ -134,9 +134,6 @@ internal class PluginManager : IInternalDisposableService
this.configuration.PluginTestingOptIns ??= new();
this.MainRepo = PluginRepository.CreateMainRepo(this.happyHttpClient);
- // NET8 CHORE
- // this.ApplyPatches();
-
registerStartupBlocker(
Task.Run(this.LoadAndStartLoadSyncPlugins),
"Waiting for plugins that asked to be loaded before the game.");
@@ -433,10 +430,6 @@ internal class PluginManager : IInternalDisposableService
await Task.WhenAll(disposablePlugins.Select(plugin => plugin.DisposeAsync().AsTask()))
.SuppressException();
}
-
- // NET8 CHORE
- // this.assemblyLocationMonoHook?.Dispose();
- // this.assemblyCodeBaseMonoHook?.Dispose();
}
///
@@ -876,9 +869,6 @@ internal class PluginManager : IInternalDisposableService
this.installedPluginsList.Remove(plugin);
}
- // NET8 CHORE
- // PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty, out _);
-
this.NotifyinstalledPluginsListChanged();
this.NotifyAvailablePluginsChanged();
}
@@ -1677,8 +1667,6 @@ internal class PluginManager : IInternalDisposableService
}
catch (InvalidPluginException)
{
- // NET8 CHORE
- // PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty, out _);
throw;
}
catch (BannedPluginException)
@@ -1724,8 +1712,6 @@ internal class PluginManager : IInternalDisposableService
}
else
{
- // NET8 CHORE
- // PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty, out _);
throw;
}
}
@@ -1934,114 +1920,3 @@ internal class PluginManager : IInternalDisposableService
public static string DalamudPluginUpdateFailed(string name, Version version, string why) => Loc.Localize("DalamudPluginUpdateFailed", " 》 {0} update to v{1} failed ({2}).").Format(name, version, why);
}
}
-
-// NET8 CHORE
-/*
-///
-/// Class responsible for loading and unloading plugins.
-/// This contains the assembly patching functionality to resolve assembly locations.
-///
-internal partial class PluginManager
-{
- ///
- /// A mapping of plugin assembly name to patch data. Used to fill in missing data due to loading
- /// plugins via byte[].
- ///
- internal static readonly ConcurrentDictionary PluginLocations = new();
-
- private MonoMod.RuntimeDetour.Hook? assemblyLocationMonoHook;
- private MonoMod.RuntimeDetour.Hook? assemblyCodeBaseMonoHook;
-
- ///
- /// Patch method for internal class RuntimeAssembly.Location, also known as Assembly.Location.
- /// This patch facilitates resolving the assembly location for plugins that are loaded via byte[].
- /// It should never be called manually.
- ///
- /// A delegate that acts as the original method.
- /// The equivalent of `this`.
- /// The plugin location, or the result from the original method.
- private static string AssemblyLocationPatch(Func orig, Assembly self)
- {
- var result = orig(self);
-
- if (string.IsNullOrEmpty(result))
- {
- foreach (var assemblyName in GetStackFrameAssemblyNames())
- {
- if (PluginLocations.TryGetValue(assemblyName, out var data))
- {
- result = data.Location;
- break;
- }
- }
- }
-
- result ??= string.Empty;
-
- Log.Verbose($"Assembly.Location // {self.FullName} // {result}");
- return result;
- }
-
- ///
- /// Patch method for internal class RuntimeAssembly.CodeBase, also known as Assembly.CodeBase.
- /// This patch facilitates resolving the assembly location for plugins that are loaded via byte[].
- /// It should never be called manually.
- ///
- /// A delegate that acts as the original method.
- /// The equivalent of `this`.
- /// The plugin code base, or the result from the original method.
- private static string AssemblyCodeBasePatch(Func orig, Assembly self)
- {
- var result = orig(self);
-
- if (string.IsNullOrEmpty(result))
- {
- foreach (var assemblyName in GetStackFrameAssemblyNames())
- {
- if (PluginLocations.TryGetValue(assemblyName, out var data))
- {
- result = data.CodeBase;
- break;
- }
- }
- }
-
- result ??= string.Empty;
-
- Log.Verbose($"Assembly.CodeBase // {self.FullName} // {result}");
- return result;
- }
-
- private static IEnumerable GetStackFrameAssemblyNames()
- {
- var stackTrace = new StackTrace();
- var stackFrames = stackTrace.GetFrames();
-
- foreach (var stackFrame in stackFrames)
- {
- var methodBase = stackFrame.GetMethod();
- if (methodBase == null)
- continue;
-
- yield return methodBase.Module.Assembly.FullName!;
- }
- }
-
- private void ApplyPatches()
- {
- var targetType = typeof(PluginManager).Assembly.GetType();
-
- var locationTarget = targetType.GetProperty(nameof(Assembly.Location))!.GetGetMethod();
- var locationPatch = typeof(PluginManager).GetMethod(nameof(AssemblyLocationPatch), BindingFlags.NonPublic | BindingFlags.Static);
- this.assemblyLocationMonoHook = new MonoMod.RuntimeDetour.Hook(locationTarget, locationPatch);
-
-#pragma warning disable CS0618
-#pragma warning disable SYSLIB0012
- var codebaseTarget = targetType.GetProperty(nameof(Assembly.CodeBase))?.GetGetMethod();
-#pragma warning restore SYSLIB0012
-#pragma warning restore CS0618
- var codebasePatch = typeof(PluginManager).GetMethod(nameof(AssemblyCodeBasePatch), BindingFlags.NonPublic | BindingFlags.Static);
- this.assemblyCodeBaseMonoHook = new MonoMod.RuntimeDetour.Hook(codebaseTarget, codebasePatch);
- }
-}
-*/
diff --git a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs
index ed3a94994..43bba0a5b 100644
--- a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs
+++ b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs
@@ -382,10 +382,6 @@ internal class LocalPlugin : IAsyncDisposable
}
}
- // Update the location for the Location and CodeBase patches
- // NET8 CHORE
- // PluginManager.PluginLocations[this.pluginType.Assembly.FullName] = new PluginPatchData(this.DllFile);
-
this.dalamudInterface = new(this, reason);
this.serviceScope = ioc.GetScope();
From b02194ca6aa90a5c976146632ef44e5b195a610e Mon Sep 17 00:00:00 2001
From: goat
Date: Thu, 26 Dec 2024 13:09:06 +0100
Subject: [PATCH 29/88] DalamudInterface doesn't need DataManager
---
Dalamud/Interface/Internal/DalamudInterface.cs | 3 ---
1 file changed, 3 deletions(-)
diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs
index 0aa10f514..d432d9d4c 100644
--- a/Dalamud/Interface/Internal/DalamudInterface.cs
+++ b/Dalamud/Interface/Internal/DalamudInterface.cs
@@ -57,7 +57,6 @@ internal class DalamudInterface : IInternalDisposableService
private readonly Dalamud dalamud;
private readonly DalamudConfiguration configuration;
private readonly InterfaceManager interfaceManager;
- private readonly DataManager dataManager;
private readonly ChangelogWindow changelogWindow;
private readonly ColorDemoWindow colorDemoWindow;
@@ -99,7 +98,6 @@ internal class DalamudInterface : IInternalDisposableService
DalamudConfiguration configuration,
FontAtlasFactory fontAtlasFactory,
InterfaceManager interfaceManager,
- DataManager dataManager,
PluginImageCache pluginImageCache,
DalamudAssetManager dalamudAssetManager,
Game.Framework framework,
@@ -112,7 +110,6 @@ internal class DalamudInterface : IInternalDisposableService
this.dalamud = dalamud;
this.configuration = configuration;
this.interfaceManager = interfaceManager;
- this.dataManager = dataManager;
this.WindowSystem = new WindowSystem("DalamudCore");
From 1d9116f0a0b01d29cb8af5c9d9d44d49e794769c Mon Sep 17 00:00:00 2001
From: goat
Date: Thu, 26 Dec 2024 13:29:54 +0100
Subject: [PATCH 30/88] unhandled exceptions when calling Draw() must be fatal
---
Dalamud/Interface/Internal/InterfaceManager.cs | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs
index 36f48f9b8..65f2da705 100644
--- a/Dalamud/Interface/Internal/InterfaceManager.cs
+++ b/Dalamud/Interface/Internal/InterfaceManager.cs
@@ -1142,7 +1142,18 @@ internal partial class InterfaceManager : IInternalDisposableService
if (this.IsDispatchingEvents)
{
- this.Draw?.Invoke();
+ try
+ {
+ this.Draw?.Invoke();
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex, "Error when invoking global Draw");
+
+ // We should always handle this in the callbacks.
+ Util.Fatal("An internal error occurred while drawing the Dalamud UI and the game must close.\nPlease report this error.", "Dalamud");
+ }
+
Service.GetNullable()?.Draw();
}
}
From ce5ee71c91dc85ebaff62240e2553e6ca368bd80 Mon Sep 17 00:00:00 2001
From: goat
Date: Thu, 26 Dec 2024 13:48:28 +0100
Subject: [PATCH 31/88] patch NNBSP number separator out of cultures that use
it (fixes #2157)
---
Dalamud/EntryPoint.cs | 3 +++
Dalamud/Utility/CultureFixes.cs | 45 +++++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+)
create mode 100644 Dalamud/Utility/CultureFixes.cs
diff --git a/Dalamud/EntryPoint.cs b/Dalamud/EntryPoint.cs
index 512acd4cc..6d5c219dd 100644
--- a/Dalamud/EntryPoint.cs
+++ b/Dalamud/EntryPoint.cs
@@ -178,6 +178,9 @@ public sealed class EntryPoint
throw new Exception("Working directory was invalid");
Reloaded.Hooks.Tools.Utilities.FasmBasePath = new DirectoryInfo(info.WorkingDirectory);
+
+ // Apply common fixes for culture issues
+ CultureFixes.Apply();
// This is due to GitHub not supporting TLS 1.0, so we enable all TLS versions globally
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls;
diff --git a/Dalamud/Utility/CultureFixes.cs b/Dalamud/Utility/CultureFixes.cs
new file mode 100644
index 000000000..0c048ed38
--- /dev/null
+++ b/Dalamud/Utility/CultureFixes.cs
@@ -0,0 +1,45 @@
+using System.Globalization;
+
+namespace Dalamud.Utility;
+
+///
+/// Class containing fixes for culture-specific issues.
+///
+internal static class CultureFixes
+{
+ ///
+ /// Apply all fixes.
+ ///
+ public static void Apply()
+ {
+ PatchNumberSeparator();
+ }
+
+ private static void PatchNumberSeparator()
+ {
+ // Reset formatting specifier for the "digit grouping symbol" to an empty string
+ // for cultures that use a narrow no-break space (U+202F).
+ // This glyph is not present in any game fonts and not in the range for our Noto
+ // so it will be rendered as a geta (=) instead. That's a hack, but it works and
+ // doesn't look as weird.
+ void PatchCulture(CultureInfo info)
+ {
+ const string invalidGroupSeparator = "\u202F";
+ const string replacedGroupSeparator = " ";
+ if (info.NumberFormat.NumberGroupSeparator == invalidGroupSeparator)
+ info.NumberFormat.NumberGroupSeparator = replacedGroupSeparator;
+
+ if (info.NumberFormat.NumberDecimalSeparator == invalidGroupSeparator)
+ info.NumberFormat.NumberDecimalSeparator = replacedGroupSeparator;
+
+ if (info.NumberFormat.CurrencyGroupSeparator == invalidGroupSeparator)
+ info.NumberFormat.CurrencyGroupSeparator = replacedGroupSeparator;
+
+ if (info.NumberFormat.CurrencyDecimalSeparator == invalidGroupSeparator)
+ info.NumberFormat.CurrencyDecimalSeparator = replacedGroupSeparator;
+ }
+
+ PatchCulture(CultureInfo.CurrentCulture);
+ PatchCulture(CultureInfo.CurrentUICulture);
+ }
+}
From 2e2feb144f45dd1a46c2940a6d0110d724b74f08 Mon Sep 17 00:00:00 2001
From: goat
Date: Thu, 26 Dec 2024 14:11:14 +0100
Subject: [PATCH 32/88] fix some warnings
---
Dalamud/Game/ClientState/ClientState.cs | 1 -
Dalamud/Game/Text/XivChatEntry.cs | 4 ++--
.../Components/ImGuiComponents.IconButton.cs | 10 +++++++--
.../ImGuiComponents.IconButtonSelect.cs | 3 +++
.../Windows/Data/Widgets/IconBrowserWidget.cs | 7 +++----
.../Windows/Data/Widgets/SeFontTestWidget.cs | 6 +++---
.../Widgets/DevPluginsSettingsEntry.cs | 21 +++++++++----------
.../Internal/AutoUpdate/AutoUpdateManager.cs | 9 ++++----
Dalamud/Utility/Util.cs | 13 ++++++------
9 files changed, 40 insertions(+), 34 deletions(-)
diff --git a/Dalamud/Game/ClientState/ClientState.cs b/Dalamud/Game/ClientState/ClientState.cs
index c898e107a..da9873d8d 100644
--- a/Dalamud/Game/ClientState/ClientState.cs
+++ b/Dalamud/Game/ClientState/ClientState.cs
@@ -48,7 +48,6 @@ internal sealed class ClientState : IInternalDisposableService, IClientState
private bool lastConditionNone = true;
-
[ServiceManager.ServiceConstructor]
private unsafe ClientState(TargetSigScanner sigScanner, Dalamud dalamud, GameLifecycle lifecycle)
{
diff --git a/Dalamud/Game/Text/XivChatEntry.cs b/Dalamud/Game/Text/XivChatEntry.cs
index 7932ead72..d4ec751f3 100644
--- a/Dalamud/Game/Text/XivChatEntry.cs
+++ b/Dalamud/Game/Text/XivChatEntry.cs
@@ -36,12 +36,12 @@ public sealed class XivChatEntry
}
///
- /// Gets or Sets the name payloads
+ /// Gets or sets the name payloads.
///
public byte[] NameBytes { get; set; } = [];
///
- /// Gets or Sets the message payloads.
+ /// Gets or sets the message payloads.
///
public byte[] MessageBytes { get; set; } = [];
diff --git a/Dalamud/Interface/Components/ImGuiComponents.IconButton.cs b/Dalamud/Interface/Components/ImGuiComponents.IconButton.cs
index 10f177590..3e61e16bb 100644
--- a/Dalamud/Interface/Components/ImGuiComponents.IconButton.cs
+++ b/Dalamud/Interface/Components/ImGuiComponents.IconButton.cs
@@ -182,7 +182,10 @@ public static partial class ImGuiComponents
///
/// Icon to show.
/// Text to show.
- /// Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon & text.
+ ///
+ /// Sets the size of the button. If either dimension is set to 0,
+ /// that dimension will conform to the size of the icon and text.
+ ///
/// Indicator if button is clicked.
public static bool IconButtonWithText(FontAwesomeIcon icon, string text, Vector2 size) => IconButtonWithText(icon, text, null, null, null, size);
@@ -194,7 +197,10 @@ public static partial class ImGuiComponents
/// The default color of the button.
/// The color of the button when active.
/// The color of the button when hovered.
- /// Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon & text.
+ ///
+ /// Sets the size of the button. If either dimension is set to 0,
+ /// that dimension will conform to the size of the icon and text.
+ ///
/// Indicator if button is clicked.
public static bool IconButtonWithText(FontAwesomeIcon icon, string text, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null, Vector2? size = null)
{
diff --git a/Dalamud/Interface/Components/ImGuiComponents.IconButtonSelect.cs b/Dalamud/Interface/Components/ImGuiComponents.IconButtonSelect.cs
index ad83c7201..99050473f 100644
--- a/Dalamud/Interface/Components/ImGuiComponents.IconButtonSelect.cs
+++ b/Dalamud/Interface/Components/ImGuiComponents.IconButtonSelect.cs
@@ -8,6 +8,9 @@ using ImGuiNET;
namespace Dalamud.Interface.Components;
+///
+/// ImGui component used to create a radio-like input that uses icon buttons.
+///
public static partial class ImGuiComponents
{
///
diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/IconBrowserWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/IconBrowserWidget.cs
index ff34574b5..3f510b088 100644
--- a/Dalamud/Interface/Internal/Windows/Data/Widgets/IconBrowserWidget.cs
+++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/IconBrowserWidget.cs
@@ -18,7 +18,7 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets;
public class IconBrowserWidget : IDataWindowWidget
{
private const int MaxIconId = 250_000;
-
+
private Vector2 iconSize = new(64.0f, 64.0f);
private Vector2 editIconSize = new(64.0f, 64.0f);
@@ -126,7 +126,6 @@ public class IconBrowserWidget : IDataWindowWidget
this.valueRange = null;
}
-
ImGui.NextColumn();
ImGui.PushItemWidth(ImGui.GetContentRegionAvail().X);
if (ImGui.InputInt("##StopRange", ref this.stopRange, 0, 0))
@@ -204,7 +203,7 @@ public class IconBrowserWidget : IDataWindowWidget
ImGui.GetColorU32(ImGuiColors.DalamudRed),
iconText);
}
-
+
if (ImGui.IsItemHovered())
ImGui.SetTooltip($"{iconId}\n{exc}".Replace("%", "%%"));
@@ -224,7 +223,7 @@ public class IconBrowserWidget : IDataWindowWidget
cursor + ((this.iconSize - textSize) / 2),
color,
text);
-
+
if (ImGui.IsItemHovered())
ImGui.SetTooltip(iconId.ToString());
diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeFontTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeFontTestWidget.cs
index 69282a8e8..35a2a616e 100644
--- a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeFontTestWidget.cs
+++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeFontTestWidget.cs
@@ -1,7 +1,7 @@
-using Dalamud.Game.Text;
-using ImGuiNET;
+using System.Linq;
-using System.Linq;
+using Dalamud.Game.Text;
+using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Data.Widgets;
diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs
index 101b21d38..4a78735f6 100644
--- a/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs
+++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs
@@ -196,6 +196,14 @@ public class DevPluginsSettingsEntry : SettingsEntry
}
}
+ public override void PostDraw()
+ {
+ this.fileDialogManager.Draw();
+ }
+
+ private static bool ValidDevPluginPath(string path)
+ => Path.IsPathRooted(path) && Path.GetExtension(path) == ".dll";
+
private void AddDevPlugin()
{
if (this.devPluginLocations.Any(
@@ -223,16 +231,7 @@ public class DevPluginsSettingsEntry : SettingsEntry
this.devPluginTempLocation = string.Empty;
}
- var config = Service.Get();
- if (!config.ImGuiAssertsEnabledAtStartup.HasValue)
- config.ImGuiAssertsEnabledAtStartup = true;
+ // Enable ImGui asserts if a dev plugin is added, if no choice was made prior
+ Service.Get().ImGuiAssertsEnabledAtStartup ??= true;
}
-
- public override void PostDraw()
- {
- this.fileDialogManager.Draw();
- }
-
- private static bool ValidDevPluginPath(string path)
- => Path.IsPathRooted(path) && Path.GetExtension(path) == ".dll";
}
diff --git a/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs b/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs
index 99850ddb4..ce135b947 100644
--- a/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs
+++ b/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs
@@ -72,6 +72,8 @@ internal class AutoUpdateManager : IServiceType
private readonly IConsoleVariable isDryRun;
+ private readonly Task openInstallerWindowLinkTask;
+
private DateTime? loginTime;
private DateTime? nextUpdateCheckTime;
private DateTime? unblockedSince;
@@ -82,8 +84,6 @@ internal class AutoUpdateManager : IServiceType
private Task? autoUpdateTask;
- private readonly Task openInstallerWindowLink;
-
///
/// Initializes a new instance of the class.
///
@@ -99,7 +99,7 @@ internal class AutoUpdateManager : IServiceType
});
Service.GetAsync().ContinueWith(t => { t.Result.Update += this.OnUpdate; });
- this.openInstallerWindowLink =
+ this.openInstallerWindowLinkTask =
Service.GetAsync().ContinueWith(
chatGuiTask => chatGuiTask.Result.AddChatLinkHandler(
"Dalamud",
@@ -109,7 +109,6 @@ internal class AutoUpdateManager : IServiceType
Service.GetNullable()?.OpenPluginInstallerTo(PluginInstallerOpenKind.InstalledPlugins);
}));
-
this.isDryRun = console.AddVariable("dalamud.autoupdate.dry_run", "Simulate updates instead", false);
console.AddCommand("dalamud.autoupdate.trigger_login", "Trigger a login event", () =>
{
@@ -441,7 +440,7 @@ internal class AutoUpdateManager : IServiceType
new TextPayload(Locs.NotificationContentUpdatesAvailableMinimized(updatablePlugins.Count)),
new TextPayload(" ["),
new UIForegroundPayload(500),
- this.openInstallerWindowLink.Result,
+ this.openInstallerWindowLinkTask.Result,
new TextPayload(Loc.Localize("DalamudInstallerHelp", "Open the plugin installer")),
RawPayload.LinkTerminator,
new UIForegroundPayload(0),
diff --git a/Dalamud/Utility/Util.cs b/Dalamud/Utility/Util.cs
index d5e14e212..d53828858 100644
--- a/Dalamud/Utility/Util.cs
+++ b/Dalamud/Utility/Util.cs
@@ -19,6 +19,7 @@ using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility;
+using Dalamud.Interface.Utility.Raii;
using Dalamud.Support;
using ImGuiNET;
using Lumina.Excel.Sheets;
@@ -28,8 +29,6 @@ using Windows.Win32.Storage.FileSystem;
using Windows.Win32.System.Memory;
using Windows.Win32.System.Ole;
-using Dalamud.Interface.Utility.Raii;
-
using static TerraFX.Interop.Windows.Windows;
using Win32_PInvoke = Windows.Win32.PInvoke;
@@ -139,11 +138,11 @@ public static class Util
public static string GetScmVersion()
{
if (scmVersionInternal != null) return scmVersionInternal;
-
+
var asm = typeof(Util).Assembly;
var attrs = asm.GetCustomAttributes();
- return scmVersionInternal = attrs.First(a => a.Key == "SCMVersion").Value
+ return scmVersionInternal = attrs.First(a => a.Key == "SCMVersion").Value
?? asm.GetName().Version!.ToString();
}
@@ -853,7 +852,7 @@ public static class Util
// ignore
}
}
-
+
///
/// Print formatted IGameObject Information to ImGui.
///
@@ -1051,7 +1050,8 @@ public static class Util
}
}
- private static unsafe void ShowSpanEntryPrivate(ulong addr, IList path, int offset, Span spanobj) {
+ private static unsafe void ShowSpanEntryPrivate(ulong addr, IList path, int offset, Span spanobj)
+ {
const int batchSize = 20;
if (spanobj.Length > batchSize)
{
@@ -1221,6 +1221,7 @@ public static class Util
ImGui.TextDisabled($"[0x{offset.Value:X}]");
ImGui.SameLine();
}
+
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.9f, 1), $"{f.FieldType.Name}");
}
From b3c0a8c20758bda2a752868c472f5f58b27fe9af Mon Sep 17 00:00:00 2001
From: goat
Date: Thu, 26 Dec 2024 14:14:16 +0100
Subject: [PATCH 33/88] editorconfig: trim trailing whitespace
---
.editorconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/.editorconfig b/.editorconfig
index 141e8c9c9..7b1cbadda 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -6,6 +6,7 @@ charset = utf-8
end_of_line = lf
insert_final_newline = true
+trim_trailing_whitespace = true
# 4 space indentation
indent_style = space
From 0a3e88efca62441e72ea4b995d1ead51c4f7a418 Mon Sep 17 00:00:00 2001
From: goat
Date: Thu, 26 Dec 2024 15:26:22 +0100
Subject: [PATCH 34/88] clone culture to apply fixes The default cultures are
read-only
---
Dalamud/Utility/CultureFixes.cs | 31 +++++++++++++++++++------------
1 file changed, 19 insertions(+), 12 deletions(-)
diff --git a/Dalamud/Utility/CultureFixes.cs b/Dalamud/Utility/CultureFixes.cs
index 0c048ed38..133e79c71 100644
--- a/Dalamud/Utility/CultureFixes.cs
+++ b/Dalamud/Utility/CultureFixes.cs
@@ -12,34 +12,41 @@ internal static class CultureFixes
///
public static void Apply()
{
- PatchNumberSeparator();
+ PatchFrenchNumberSeparator();
}
- private static void PatchNumberSeparator()
+ private static void PatchFrenchNumberSeparator()
{
// Reset formatting specifier for the "digit grouping symbol" to an empty string
// for cultures that use a narrow no-break space (U+202F).
// This glyph is not present in any game fonts and not in the range for our Noto
// so it will be rendered as a geta (=) instead. That's a hack, but it works and
// doesn't look as weird.
- void PatchCulture(CultureInfo info)
+ CultureInfo PatchCulture(CultureInfo info)
{
+ var newCulture = (CultureInfo)info.Clone();
+
const string invalidGroupSeparator = "\u202F";
const string replacedGroupSeparator = " ";
+
if (info.NumberFormat.NumberGroupSeparator == invalidGroupSeparator)
- info.NumberFormat.NumberGroupSeparator = replacedGroupSeparator;
-
+ newCulture.NumberFormat.NumberGroupSeparator = replacedGroupSeparator;
+
if (info.NumberFormat.NumberDecimalSeparator == invalidGroupSeparator)
- info.NumberFormat.NumberDecimalSeparator = replacedGroupSeparator;
+ newCulture.NumberFormat.NumberDecimalSeparator = replacedGroupSeparator;
if (info.NumberFormat.CurrencyGroupSeparator == invalidGroupSeparator)
- info.NumberFormat.CurrencyGroupSeparator = replacedGroupSeparator;
-
+ newCulture.NumberFormat.CurrencyGroupSeparator = replacedGroupSeparator;
+
if (info.NumberFormat.CurrencyDecimalSeparator == invalidGroupSeparator)
- info.NumberFormat.CurrencyDecimalSeparator = replacedGroupSeparator;
+ newCulture.NumberFormat.CurrencyDecimalSeparator = replacedGroupSeparator;
+
+ return newCulture;
}
-
- PatchCulture(CultureInfo.CurrentCulture);
- PatchCulture(CultureInfo.CurrentUICulture);
+
+ CultureInfo.CurrentCulture = PatchCulture(CultureInfo.CurrentCulture);
+ CultureInfo.CurrentUICulture = PatchCulture(CultureInfo.CurrentUICulture);
+ CultureInfo.DefaultThreadCurrentCulture = CultureInfo.CurrentCulture;
+ CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CurrentUICulture;
}
}
From f98da094f416030b115e5e37356da49dda35aa42 Mon Sep 17 00:00:00 2001
From: Haselnussbomber
Date: Thu, 26 Dec 2024 16:39:54 +0100
Subject: [PATCH 35/88] Fetch market board uploader info from main thread
(#2158)
---
.../IMarketBoardUploader.cs | 12 +++-
.../UniversalisMarketBoardUploader.cs | 33 +++--------
.../Game/Network/Internal/NetworkHandlers.cs | 55 +++++++++++++++----
3 files changed, 62 insertions(+), 38 deletions(-)
diff --git a/Dalamud/Game/Network/Internal/MarketBoardUploaders/IMarketBoardUploader.cs b/Dalamud/Game/Network/Internal/MarketBoardUploaders/IMarketBoardUploader.cs
index dadfef604..adf5f0228 100644
--- a/Dalamud/Game/Network/Internal/MarketBoardUploaders/IMarketBoardUploader.cs
+++ b/Dalamud/Game/Network/Internal/MarketBoardUploaders/IMarketBoardUploader.cs
@@ -13,20 +13,26 @@ internal interface IMarketBoardUploader
/// Upload data about an item.
///
/// The item request data being uploaded.
+ /// The uploaders ContentId.
+ /// The uploaders WorldId.
/// An async task.
- Task Upload(MarketBoardItemRequest item);
+ Task Upload(MarketBoardItemRequest item, ulong uploaderId, uint worldId);
///
/// Upload tax rate data.
///
/// The tax rate data being uploaded.
+ /// The uploaders ContentId.
+ /// The uploaders WorldId.
/// An async task.
- Task UploadTax(MarketTaxRates taxRates);
+ Task UploadTax(MarketTaxRates taxRates, ulong uploaderId, uint worldId);
///
/// Upload information about a purchase this client has made.
///
/// The purchase handler data associated with the sale.
+ /// The uploaders ContentId.
+ /// The uploaders WorldId.
/// An async task.
- Task UploadPurchase(MarketBoardPurchaseHandler purchaseHandler);
+ Task UploadPurchase(MarketBoardPurchaseHandler purchaseHandler, ulong uploaderId, uint worldId);
}
diff --git a/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs b/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs
index f326c5ce0..7ecb9c397 100644
--- a/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs
+++ b/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
-using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
@@ -33,21 +32,16 @@ internal class UniversalisMarketBoardUploader : IMarketBoardUploader
this.httpClient = happyHttpClient.SharedHttpClient;
///
- public async Task Upload(MarketBoardItemRequest request)
+ public async Task Upload(MarketBoardItemRequest request, ulong uploaderId, uint worldId)
{
- var clientState = Service.GetNullable();
- if (clientState == null)
- return;
-
Log.Verbose("Starting Universalis upload");
- var uploader = clientState.LocalContentId;
// ====================================================================================
var uploadObject = new UniversalisItemUploadRequest
{
- WorldId = clientState.LocalPlayer?.CurrentWorld.RowId ?? 0,
- UploaderId = uploader.ToString(),
+ WorldId = worldId,
+ UploaderId = uploaderId.ToString(),
ItemId = request.CatalogId,
Listings = [],
Sales = [],
@@ -117,18 +111,12 @@ internal class UniversalisMarketBoardUploader : IMarketBoardUploader
}
///
- public async Task UploadTax(MarketTaxRates taxRates)
+ public async Task UploadTax(MarketTaxRates taxRates, ulong uploaderId, uint worldId)
{
- var clientState = Service.GetNullable();
- if (clientState == null)
- return;
-
- // ====================================================================================
-
var taxUploadObject = new UniversalisTaxUploadRequest
{
- WorldId = clientState.LocalPlayer?.CurrentWorld.RowId ?? 0,
- UploaderId = clientState.LocalContentId.ToString(),
+ WorldId = worldId,
+ UploaderId = uploaderId.ToString(),
TaxData = new UniversalisTaxData
{
LimsaLominsa = taxRates.LimsaLominsaTax,
@@ -159,14 +147,9 @@ internal class UniversalisMarketBoardUploader : IMarketBoardUploader
/// to track the available listings, that is done via the listings packet. All this does is remove
/// a listing, or delete it, when a purchase has been made.
///
- public async Task UploadPurchase(MarketBoardPurchaseHandler purchaseHandler)
+ public async Task UploadPurchase(MarketBoardPurchaseHandler purchaseHandler, ulong uploaderId, uint worldId)
{
- var clientState = Service.GetNullable();
- if (clientState == null)
- return;
-
var itemId = purchaseHandler.CatalogId;
- var worldId = clientState.LocalPlayer?.CurrentWorld.RowId ?? 0;
// ====================================================================================
@@ -176,7 +159,7 @@ internal class UniversalisMarketBoardUploader : IMarketBoardUploader
Quantity = purchaseHandler.ItemQuantity,
ListingId = purchaseHandler.ListingId.ToString(),
RetainerId = purchaseHandler.RetainerId.ToString(),
- UploaderId = clientState.LocalContentId.ToString(),
+ UploaderId = uploaderId.ToString(),
};
var deletePath = $"/api/{worldId}/{itemId}/delete";
diff --git a/Dalamud/Game/Network/Internal/NetworkHandlers.cs b/Dalamud/Game/Network/Internal/NetworkHandlers.cs
index a25444f10..2ba7f2587 100644
--- a/Dalamud/Game/Network/Internal/NetworkHandlers.cs
+++ b/Dalamud/Game/Network/Internal/NetworkHandlers.cs
@@ -16,8 +16,11 @@ using Dalamud.Hooking;
using Dalamud.Networking.Http;
using Dalamud.Utility;
+using FFXIVClientStructs.FFXIV.Client.Game.Control;
using FFXIVClientStructs.FFXIV.Client.Game.InstanceContent;
+using FFXIVClientStructs.FFXIV.Client.Game.UI;
using FFXIVClientStructs.FFXIV.Client.Network;
+using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using FFXIVClientStructs.FFXIV.Client.UI.Info;
using Lumina.Excel.Sheets;
using Serilog;
@@ -264,6 +267,33 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
this.cfPopHook.Dispose();
}
+ private static (ulong UploaderId, uint WorldId) GetUploaderInfo()
+ {
+ var agentLobby = AgentLobby.Instance();
+
+ var uploaderId = agentLobby->LobbyData.ContentId;
+ if (uploaderId == 0)
+ {
+ var playerState = PlayerState.Instance();
+ if (playerState->IsLoaded == 1)
+ {
+ uploaderId = playerState->ContentId;
+ }
+ }
+
+ var worldId = agentLobby->LobbyData.CurrentWorldId;
+ if (worldId == 0)
+ {
+ var localPlayer = Control.GetLocalPlayer();
+ if (localPlayer != null)
+ {
+ worldId = localPlayer->CurrentWorld;
+ }
+ }
+
+ return (uploaderId, worldId);
+ }
+
private unsafe nint CfPopDetour(PublicContentDirector.EnterContentInfoPacket* packetData)
{
var result = this.cfPopHook.OriginalDisposeSafe(packetData);
@@ -424,14 +454,14 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
startObservable
.And(this.OnMarketBoardSalesBatch(startObservable))
.And(this.OnMarketBoardListingsBatch(startObservable))
- .Then((request, sales, listings) => (request, sales, listings)))
+ .Then((request, sales, listings) => (request, sales, listings, GetUploaderInfo())))
.Where(this.ShouldUpload)
.SubscribeOn(ThreadPoolScheduler.Instance)
.Subscribe(
data =>
{
- var (request, sales, listings) = data;
- this.UploadMarketBoardData(request, sales, listings);
+ var (request, sales, listings, uploaderInfo) = data;
+ this.UploadMarketBoardData(request, sales, listings, uploaderInfo.UploaderId, uploaderInfo.WorldId);
},
ex => Log.Error(ex, "Failed to handle Market Board item request event"));
}
@@ -439,7 +469,9 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
private void UploadMarketBoardData(
MarketBoardItemRequest request,
(uint CatalogId, ICollection Sales) sales,
- ICollection listings)
+ ICollection listings,
+ ulong uploaderId,
+ uint worldId)
{
var catalogId = sales.CatalogId;
if (listings.Count != request.AmountToArrive)
@@ -460,7 +492,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
request.Listings.AddRange(listings);
request.History.AddRange(sales.Sales);
- Task.Run(() => this.uploader.Upload(request))
+ Task.Run(() => this.uploader.Upload(request, uploaderId, worldId))
.ContinueWith(
task => Log.Error(task.Exception, "Market Board offerings data upload failed"),
TaskContinuationOptions.OnlyOnFaulted);
@@ -469,11 +501,14 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
private IDisposable HandleMarketTaxRates()
{
return this.MbTaxesObservable
+ .Select((taxes) => (taxes, GetUploaderInfo()))
.Where(this.ShouldUpload)
.SubscribeOn(ThreadPoolScheduler.Instance)
.Subscribe(
- taxes =>
+ data =>
{
+ var (taxes, uploaderInfo) = data;
+
Log.Verbose(
"MarketTaxRates: limsa#{0} grid#{1} uldah#{2} ish#{3} kugane#{4} cr#{5} sh#{6}",
taxes.LimsaLominsaTax,
@@ -484,7 +519,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
taxes.CrystariumTax,
taxes.SharlayanTax);
- Task.Run(() => this.uploader.UploadTax(taxes))
+ Task.Run(() => this.uploader.UploadTax(taxes, uploaderInfo.UploaderId, uploaderInfo.WorldId))
.ContinueWith(
task => Log.Error(task.Exception, "Market Board tax data upload failed"),
TaskContinuationOptions.OnlyOnFaulted);
@@ -495,13 +530,13 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
private IDisposable HandleMarketBoardPurchaseHandler()
{
return this.MbPurchaseSentObservable
- .Zip(this.MbPurchaseObservable)
+ .Zip(this.MbPurchaseObservable, (handler, purchase) => (handler, purchase, GetUploaderInfo()))
.Where(this.ShouldUpload)
.SubscribeOn(ThreadPoolScheduler.Instance)
.Subscribe(
data =>
{
- var (handler, purchase) = data;
+ var (handler, purchase, uploaderInfo) = data;
var sameQty = purchase.ItemQuantity == handler.ItemQuantity;
var itemMatch = purchase.CatalogId == handler.CatalogId;
@@ -516,7 +551,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
handler.CatalogId,
handler.PricePerUnit * purchase.ItemQuantity,
handler.ListingId);
- Task.Run(() => this.uploader.UploadPurchase(handler))
+ Task.Run(() => this.uploader.UploadPurchase(handler, uploaderInfo.UploaderId, uploaderInfo.WorldId))
.ContinueWith(
task => Log.Error(task.Exception, "Market Board purchase data upload failed"),
TaskContinuationOptions.OnlyOnFaulted);
From f3d7c6f2ea81660e4e664dd076064ad897447be8 Mon Sep 17 00:00:00 2001
From: goat
Date: Thu, 26 Dec 2024 17:05:10 +0100
Subject: [PATCH 36/88] don't access nullptr addon when shutting down early
---
Dalamud/Game/Gui/ContextMenu/ContextMenu.cs | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/Dalamud/Game/Gui/ContextMenu/ContextMenu.cs b/Dalamud/Game/Gui/ContextMenu/ContextMenu.cs
index 604af5ac7..fb78e6b80 100644
--- a/Dalamud/Game/Gui/ContextMenu/ContextMenu.cs
+++ b/Dalamud/Game/Gui/ContextMenu/ContextMenu.cs
@@ -47,9 +47,9 @@ internal sealed unsafe class ContextMenu : IInternalDisposableService, IContextM
}
private delegate ushort AtkModuleVf22OpenAddonByAgentDelegate(AtkModule* module, byte* addonName, int valueCount, AtkValue* values, AgentInterface* agent, nint a7, bool a8);
-
+
private delegate bool AddonContextMenuOnMenuSelectedDelegate(AddonContextMenu* addon, int selectedIdx, byte a3);
-
+
private delegate ushort RaptureAtkModuleOpenAddonDelegate(RaptureAtkModule* a1, uint addonNameId, uint valueCount, AtkValue* values, AgentInterface* parentAgent, ulong unk, ushort parentAddonId, int unk2);
///
@@ -92,16 +92,22 @@ internal sealed unsafe class ContextMenu : IInternalDisposableService, IContextM
///
void IInternalDisposableService.DisposeService()
{
+ this.atkModuleVf22OpenAddonByAgentHook.Dispose();
+ this.addonContextMenuOnMenuSelectedHook.Dispose();
+
var manager = RaptureAtkUnitManager.Instance();
+ if (manager == null)
+ return;
+
var menu = manager->GetAddonByName("ContextMenu");
var submenu = manager->GetAddonByName("AddonContextSub");
+ if (menu == null || submenu == null)
+ return;
+
if (menu->IsVisible)
menu->FireCallbackInt(-1);
if (submenu->IsVisible)
submenu->FireCallbackInt(-1);
-
- this.atkModuleVf22OpenAddonByAgentHook.Dispose();
- this.addonContextMenuOnMenuSelectedHook.Dispose();
}
///
From 10f4009a0c03be9e165f90e14811bda2e6972733 Mon Sep 17 00:00:00 2001
From: goat
Date: Thu, 26 Dec 2024 17:16:19 +0100
Subject: [PATCH 37/88] don't implicitly depend on DataManager in data widget
load functions
---
.../Internal/Asserts/RenderScopes.cs | 23 +++++++++++++++++++
.../Widgets/SeStringRendererTestWidget.cs | 10 ++++----
.../Windows/Data/Widgets/UIColorWidget.cs | 18 ++++++---------
3 files changed, 35 insertions(+), 16 deletions(-)
create mode 100644 Dalamud/Interface/Internal/Asserts/RenderScopes.cs
diff --git a/Dalamud/Interface/Internal/Asserts/RenderScopes.cs b/Dalamud/Interface/Internal/Asserts/RenderScopes.cs
new file mode 100644
index 000000000..1e0448e87
--- /dev/null
+++ b/Dalamud/Interface/Internal/Asserts/RenderScopes.cs
@@ -0,0 +1,23 @@
+using System.Diagnostics;
+
+namespace Dalamud.Interface.Internal.Asserts;
+
+public static class RenderScopes
+{
+ private static RenderScopeFrame currentFrame = new();
+ private static RenderScopeFrame lastFrame = new();
+
+ public static RenderScopeFrame GetLastFrame() => lastFrame;
+
+ public static RenderScopeFrame GetCurrentFrame() => currentFrame;
+
+ public static void NewFrame()
+ {
+ //Debug.Assert(currentFrame.IsRoot, "NewFrame() but we didn't pop all the way to .");
+ }
+
+ public class RenderScopeFrame
+ {
+
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs
index 5afda62ac..323c9ce62 100644
--- a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs
+++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs
@@ -15,7 +15,6 @@ using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET;
-using Lumina.Excel;
using Lumina.Excel.Sheets;
using Lumina.Text;
using Lumina.Text.Payloads;
@@ -31,7 +30,6 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget
private static readonly string[] ThemeNames = ["Dark", "Light", "Classic FF", "Clear Blue"];
private ImVectorWrapper testStringBuffer;
private string testString = string.Empty;
- private ExcelSheet addons = null!;
private ReadOnlySeString? logkind;
private SeStringDrawParams style;
private bool interactable;
@@ -51,7 +49,6 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget
public void Load()
{
this.style = new() { GetEntity = this.GetEntity };
- this.addons = Service.Get().GetExcelSheet();
this.logkind = null;
this.testString = string.Empty;
this.interactable = this.useEntity = true;
@@ -193,13 +190,16 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget
ImGui.CalcTextSize("AAAAAAAAAAAAAAAAA").X);
ImGui.TableHeadersRow();
+ var addon = Service.GetNullable()?.GetExcelSheet() ??
+ throw new InvalidOperationException("Addon sheet not loaded.");
+
var clipper = new ImGuiListClipperPtr(ImGuiNative.ImGuiListClipper_ImGuiListClipper());
- clipper.Begin(this.addons.Count);
+ clipper.Begin(addon.Count);
while (clipper.Step())
{
for (var i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
{
- var row = this.addons.GetRowAt(i);
+ var row = addon.GetRowAt(i);
ImGui.TableNextRow();
ImGui.PushID(i);
diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs
index 6b57f7a6a..d43ae50a3 100644
--- a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs
+++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs
@@ -1,5 +1,4 @@
using System.Buffers.Binary;
-using System.Linq;
using System.Numerics;
using System.Text;
@@ -7,12 +6,9 @@ using Dalamud.Data;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.ImGuiSeStringRenderer.Internal;
-using Dalamud.Interface.Utility;
-using Dalamud.Storage.Assets;
using ImGuiNET;
-using Lumina.Excel;
using Lumina.Excel.Sheets;
namespace Dalamud.Interface.Internal.Windows.Data.Widgets;
@@ -22,8 +18,6 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets;
///
internal class UiColorWidget : IDataWindowWidget
{
- private ExcelSheet colors;
-
///
public string[]? CommandShortcuts { get; init; } = ["uicolor"];
@@ -37,12 +31,14 @@ internal class UiColorWidget : IDataWindowWidget
public void Load()
{
this.Ready = true;
- this.colors = Service.Get().GetExcelSheet();
}
///
public unsafe void Draw()
{
+ var colors = Service.GetNullable()?.GetExcelSheet()
+ ?? throw new InvalidOperationException("UIColor sheet not loaded.");
+
Service.Get().CompileAndDrawWrapped(
"· Color notation is #" +
"RR" +
@@ -71,16 +67,16 @@ internal class UiColorWidget : IDataWindowWidget
ImGui.TableHeadersRow();
var clipper = new ImGuiListClipperPtr(ImGuiNative.ImGuiListClipper_ImGuiListClipper());
- clipper.Begin(this.colors.Count, ImGui.GetFrameHeightWithSpacing());
+ clipper.Begin(colors.Count, ImGui.GetFrameHeightWithSpacing());
while (clipper.Step())
{
for (var i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
{
- var row = this.colors.GetRowAt(i);
+ var row = colors.GetRowAt(i);
UIColor? adjacentRow = null;
- if (i + 1 < this.colors.Count)
+ if (i + 1 < colors.Count)
{
- var adjRow = this.colors.GetRowAt(i + 1);
+ var adjRow = colors.GetRowAt(i + 1);
if (adjRow.RowId == row.RowId + 1)
{
adjacentRow = adjRow;
From 3f3f5f4b7203c9a253b8ce277f59b5f36b12edf5 Mon Sep 17 00:00:00 2001
From: goat
Date: Thu, 26 Dec 2024 22:10:10 +0100
Subject: [PATCH 38/88] hide assert logs that spam every frame automatically,
add "verbose" mode
---
.../Internal/Asserts/AssertHandler.cs | 57 +++++++++++++++----
.../Interface/Internal/DalamudInterface.cs | 48 +++++++++-------
.../Interface/Internal/InterfaceManager.cs | 19 +++++--
3 files changed, 87 insertions(+), 37 deletions(-)
diff --git a/Dalamud/Interface/Internal/Asserts/AssertHandler.cs b/Dalamud/Interface/Internal/Asserts/AssertHandler.cs
index b0cfb462c..c1dc12206 100644
--- a/Dalamud/Interface/Internal/Asserts/AssertHandler.cs
+++ b/Dalamud/Interface/Internal/Asserts/AssertHandler.cs
@@ -15,7 +15,11 @@ namespace Dalamud.Interface.Internal.Asserts;
///
internal class AssertHandler : IDisposable
{
+ private const int HideThreshold = 20;
+ private const int HidePrintEvery = 500;
+
private readonly HashSet ignoredAsserts = [];
+ private readonly Dictionary assertCounts = new();
// Store callback to avoid it from being GC'd
private readonly AssertCallbackDelegate callback;
@@ -37,7 +41,13 @@ internal class AssertHandler : IDisposable
/// Gets or sets a value indicating whether ImGui asserts should be shown to the user.
///
public bool ShowAsserts { get; set; }
-
+
+ ///
+ /// Gets or sets a value indicating whether we want to hide asserts that occur frequently (= every update)
+ /// and whether we want to log callstacks.
+ ///
+ public bool EnableVerboseLogging { get; set; }
+
///
/// Register the cimgui assert handler with the native library.
///
@@ -62,18 +72,43 @@ internal class AssertHandler : IDisposable
private void OnImGuiAssert(string expr, string file, int line)
{
- Log.Warning("ImGui assertion failed: {Expr} at {File}:{Line}", expr, file, line);
-
- if (!this.ShowAsserts)
- return;
-
var key = $"{file}:{line}";
if (this.ignoredAsserts.Contains(key))
return;
- // TODO: It would be nice to get unmanaged stack frames here, seems hard though without pulling that
- // entire code in from the crash handler
- var originalStackTrace = new StackTrace(2).ToString();
+ Lazy stackTrace = new(() => new StackTrace(3).ToString());
+
+ if (!this.EnableVerboseLogging)
+ {
+ if (this.assertCounts.TryGetValue(key, out var count))
+ {
+ this.assertCounts[key] = count + 1;
+
+ if (count <= HideThreshold || count % HidePrintEvery == 0)
+ {
+ Log.Warning("ImGui assertion failed: {Expr} at {File}:{Line} (repeated {Count} times)",
+ expr,
+ file,
+ line,
+ count);
+ }
+ }
+ else
+ {
+ this.assertCounts[key] = 1;
+ }
+ }
+ else
+ {
+ Log.Warning("ImGui assertion failed: {Expr} at {File}:{Line}\n{StackTrace:l}",
+ expr,
+ file,
+ line,
+ stackTrace.Value);
+ }
+
+ if (!this.ShowAsserts)
+ return;
string? GetRepoUrl()
{
@@ -108,7 +143,7 @@ internal class AssertHandler : IDisposable
Text = "Break",
AllowCloseDialog = true,
};
-
+
var disableButton = new TaskDialogButton
{
Text = "Disable for this session",
@@ -132,7 +167,7 @@ internal class AssertHandler : IDisposable
{
CollapsedButtonText = "Show stack trace",
ExpandedButtonText = "Hide stack trace",
- Text = originalStackTrace,
+ Text = stackTrace.Value,
},
Text = $"Some code in a plugin or Dalamud itself has caused an internal assertion in ImGui to fail. The game will most likely crash now.\n\n{expr}\nAt: {file}:{line}",
Icon = TaskDialogIcon.Warning,
diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs
index d432d9d4c..0381164c9 100644
--- a/Dalamud/Interface/Internal/DalamudInterface.cs
+++ b/Dalamud/Interface/Internal/DalamudInterface.cs
@@ -91,7 +91,7 @@ internal class DalamudInterface : IInternalDisposableService
private bool isImPlotDrawDemoWindow = false;
private bool isImGuiTestWindowsInMonospace = false;
private bool isImGuiDrawMetricsWindow = false;
-
+
[ServiceManager.ServiceConstructor]
private DalamudInterface(
Dalamud dalamud,
@@ -112,7 +112,7 @@ internal class DalamudInterface : IInternalDisposableService
this.interfaceManager = interfaceManager;
this.WindowSystem = new WindowSystem("DalamudCore");
-
+
this.colorDemoWindow = new ColorDemoWindow() { IsOpen = false };
this.componentDemoWindow = new ComponentDemoWindow() { IsOpen = false };
this.dataWindow = new DataWindow() { IsOpen = false };
@@ -193,7 +193,7 @@ internal class DalamudInterface : IInternalDisposableService
this.creditsDarkeningAnimation.Point1 = Vector2.Zero;
this.creditsDarkeningAnimation.Point2 = new Vector2(CreditsDarkeningMaxAlpha);
-
+
// This is temporary, until we know the repercussions of vtable hooking mode
consoleManager.AddCommand(
"dalamud.interface.swapchain_mode",
@@ -212,14 +212,14 @@ internal class DalamudInterface : IInternalDisposableService
Log.Error("Unknown swapchain mode: {Mode}", mode);
return false;
}
-
+
this.configuration.QueueSave();
return true;
});
}
-
+
private delegate nint CrashDebugDelegate(nint self);
-
+
///
/// Gets the number of frames since Dalamud has loaded.
///
@@ -319,7 +319,7 @@ internal class DalamudInterface : IInternalDisposableService
this.pluginStatWindow.IsOpen = true;
this.pluginStatWindow.BringToFront();
}
-
+
///
/// Opens the on the plugin installed.
///
@@ -384,7 +384,7 @@ internal class DalamudInterface : IInternalDisposableService
this.profilerWindow.IsOpen = true;
this.profilerWindow.BringToFront();
}
-
+
///
/// Opens the .
///
@@ -696,7 +696,7 @@ internal class DalamudInterface : IInternalDisposableService
ImGui.EndMenu();
}
-
+
var logSynchronously = this.configuration.LogSynchronously;
if (ImGui.MenuItem("Log Synchronously", null, ref logSynchronously))
{
@@ -788,14 +788,14 @@ internal class DalamudInterface : IInternalDisposableService
}
ImGui.Separator();
-
+
if (ImGui.BeginMenu("Crash game"))
{
if (ImGui.MenuItem("Access Violation"))
{
Marshal.ReadByte(IntPtr.Zero);
- }
-
+ }
+
if (ImGui.MenuItem("Set UiModule to NULL"))
{
unsafe
@@ -804,7 +804,7 @@ internal class DalamudInterface : IInternalDisposableService
framework->UIModule = (UIModule*)0;
}
}
-
+
if (ImGui.MenuItem("Set UiModule to invalid ptr"))
{
unsafe
@@ -813,7 +813,7 @@ internal class DalamudInterface : IInternalDisposableService
framework->UIModule = (UIModule*)0x12345678;
}
}
-
+
if (ImGui.MenuItem("Deref nullptr in Hook"))
{
unsafe
@@ -834,7 +834,7 @@ internal class DalamudInterface : IInternalDisposableService
ImGui.PopStyleVar();
ImGui.PopStyleVar();
}
-
+
ImGui.EndMenu();
}
@@ -850,7 +850,7 @@ internal class DalamudInterface : IInternalDisposableService
{
this.OpenBranchSwitcher();
}
-
+
ImGui.MenuItem(this.dalamud.StartInfo.GameVersion?.ToString() ?? "Unknown version", false);
ImGui.MenuItem($"D: {Util.GetScmVersion()} CS: {Util.GetGitHashClientStructs()}[{FFXIVClientStructs.ThisAssembly.Git.Commits}]", false);
ImGui.MenuItem($"CLR: {Environment.Version}", false);
@@ -867,10 +867,16 @@ internal class DalamudInterface : IInternalDisposableService
ImGui.Separator();
- var val = this.interfaceManager.ShowAsserts;
- if (ImGui.MenuItem("Enable Asserts", string.Empty, ref val))
+ var showAsserts = this.interfaceManager.ShowAsserts;
+ if (ImGui.MenuItem("Enable assert popups", string.Empty, ref showAsserts))
{
- this.interfaceManager.ShowAsserts = val;
+ this.interfaceManager.ShowAsserts = showAsserts;
+ }
+
+ var enableVerboseAsserts = this.interfaceManager.EnableVerboseAssertLogging;
+ if (ImGui.MenuItem("Enable verbose assert logging", string.Empty, ref enableVerboseAsserts))
+ {
+ this.interfaceManager.EnableVerboseAssertLogging = enableVerboseAsserts;
}
var assertsEnabled = this.configuration.ImGuiAssertsEnabledAtStartup ?? false;
@@ -880,6 +886,8 @@ internal class DalamudInterface : IInternalDisposableService
this.configuration.QueueSave();
}
+ ImGui.Separator();
+
if (ImGui.MenuItem("Clear focus"))
{
ImGui.SetWindowFocus(null);
@@ -927,7 +935,7 @@ internal class DalamudInterface : IInternalDisposableService
{
this.configuration.ShowDevBarInfo = !this.configuration.ShowDevBarInfo;
}
-
+
ImGui.Separator();
if (ImGui.MenuItem("Show loading window"))
diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs
index 65f2da705..2908be34a 100644
--- a/Dalamud/Interface/Internal/InterfaceManager.cs
+++ b/Dalamud/Interface/Internal/InterfaceManager.cs
@@ -73,7 +73,7 @@ internal partial class InterfaceManager : IInternalDisposableService
public const float DefaultFontSizePx = (DefaultFontSizePt * 4.0f) / 3.0f;
private static readonly ModuleLog Log = new("INTERFACE");
-
+
private readonly ConcurrentBag deferredDisposeTextures = new();
private readonly ConcurrentBag deferredDisposeDisposables = new();
@@ -93,7 +93,7 @@ internal partial class InterfaceManager : IInternalDisposableService
private readonly ConcurrentQueue runBeforeImGuiRender = new();
private readonly ConcurrentQueue runAfterImGuiRender = new();
-
+
private readonly AssertHandler assertHandler = new();
private RawDX11Scene? scene;
@@ -276,6 +276,13 @@ internal partial class InterfaceManager : IInternalDisposableService
set => this.assertHandler.ShowAsserts = value;
}
+ ///
+ public bool EnableVerboseAssertLogging
+ {
+ get => this.assertHandler.EnableVerboseLogging;
+ set => this.assertHandler.EnableVerboseLogging = value;
+ }
+
///
/// Dispose of managed and unmanaged resources.
///
@@ -809,14 +816,14 @@ internal partial class InterfaceManager : IInternalDisposableService
});
};
}
-
+
// This will wait for scene on its own. We just wait for this.dalamudAtlas.BuildTask in this.InitScene.
_ = this.dalamudAtlas.BuildFontsAsync();
SwapChainHelper.BusyWaitForGameDeviceSwapChain();
var swapChainDesc = default(DXGI_SWAP_CHAIN_DESC);
if (SwapChainHelper.GameDeviceSwapChain->GetDesc(&swapChainDesc).SUCCEEDED)
- this.gameWindowHandle = swapChainDesc.OutputWindow;
+ this.gameWindowHandle = swapChainDesc.OutputWindow;
try
{
@@ -959,7 +966,7 @@ internal partial class InterfaceManager : IInternalDisposableService
switch (this.dalamudConfiguration.SwapChainHookMode)
{
- case SwapChainHelper.HookMode.ByteCode:
+ case SwapChainHelper.HookMode.ByteCode:
default:
{
Log.Information("Hooking using bytecode...");
@@ -1149,7 +1156,7 @@ internal partial class InterfaceManager : IInternalDisposableService
catch (Exception ex)
{
Log.Error(ex, "Error when invoking global Draw");
-
+
// We should always handle this in the callbacks.
Util.Fatal("An internal error occurred while drawing the Dalamud UI and the game must close.\nPlease report this error.", "Dalamud");
}
From 55bfe9eeb0e021c015cc12229d431a13bee0cc02 Mon Sep 17 00:00:00 2001
From: goat
Date: Fri, 27 Dec 2024 18:19:45 +0100
Subject: [PATCH 39/88] upgrade cimgui, fix IME and image rendering
---
Dalamud/Interface/Internal/DalamudIme.cs | 27 ++++++++----------------
lib/cimgui | 2 +-
2 files changed, 10 insertions(+), 19 deletions(-)
diff --git a/Dalamud/Interface/Internal/DalamudIme.cs b/Dalamud/Interface/Internal/DalamudIme.cs
index 7beb5e58b..a1c4a0a95 100644
--- a/Dalamud/Interface/Internal/DalamudIme.cs
+++ b/Dalamud/Interface/Internal/DalamudIme.cs
@@ -37,9 +37,6 @@ namespace Dalamud.Interface.Internal;
[ServiceManager.EarlyLoadedService]
internal sealed unsafe class DalamudIme : IInternalDisposableService
{
- private const int CImGuiStbTextCreateUndoOffset = 0xB57A0;
- private const int CImGuiStbTextUndoOffset = 0xB59C0;
-
private const int ImePageSize = 9;
private static readonly Dictionary WmNames =
@@ -69,11 +66,6 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
UnicodeRanges.HangulJamoExtendedB,
};
- private static readonly delegate* unmanaged
- StbTextMakeUndoReplace;
-
- private static readonly delegate* unmanaged StbTextUndo;
-
[ServiceManager.ServiceDependency]
private readonly DalamudConfiguration dalamudConfiguration = Service.Get();
@@ -134,13 +126,6 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
{
return;
}
-
- StbTextMakeUndoReplace =
- (delegate* unmanaged)
- (cimgui + CImGuiStbTextCreateUndoOffset);
- StbTextUndo =
- (delegate* unmanaged)
- (cimgui + CImGuiStbTextUndoOffset);
}
[ServiceManager.ServiceConstructor]
@@ -1031,14 +1016,14 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
(s, e) = (e, s);
}
- public void Undo() => StbTextUndo(this.ThisPtr, &this.ThisPtr->Stb);
+ public void Undo() => CustomNativeFunctions.igCustom_StbTextUndo(this.ThisPtr);
public bool MakeUndoReplace(int offset, int oldLength, int newLength)
{
if (oldLength == 0 && newLength == 0)
return false;
- StbTextMakeUndoReplace(this.ThisPtr, &this.ThisPtr->Stb, offset, oldLength, newLength);
+ CustomNativeFunctions.igCustom_StbTextMakeUndoReplace(this.ThisPtr, offset, oldLength, newLength);
return true;
}
@@ -1116,9 +1101,15 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService
private static class CustomNativeFunctions
{
- [DllImport("cimgui")]
#pragma warning disable SA1300
+ [DllImport("cimgui")]
public static extern ImGuiInputTextState* igCustom_GetInputTextState();
+
+ [DllImport("cimgui")]
+ public static extern void igCustom_StbTextMakeUndoReplace(ImGuiInputTextState* str, int where, int old_length, int new_length);
+
+ [DllImport("cimgui")]
+ public static extern void igCustom_StbTextUndo(ImGuiInputTextState* str);
#pragma warning restore SA1300
}
diff --git a/lib/cimgui b/lib/cimgui
index fd2377934..7002b2884 160000
--- a/lib/cimgui
+++ b/lib/cimgui
@@ -1 +1 @@
-Subproject commit fd2377934f2cc007982e21ab82e54b41955cb658
+Subproject commit 7002b2884e9216d8bef3e792722d88abe31788f8
From 4af9bc05dc0cd02a56fc9d93469c69cf7939d73e Mon Sep 17 00:00:00 2001
From: goat
Date: Sat, 28 Dec 2024 14:00:25 +0100
Subject: [PATCH 40/88] don't rebuild Dalamud.Boot every time, copy out of
output directory instead
---
Dalamud.Boot/Dalamud.Boot.vcxproj | 12 ++++++----
.../Internal/Asserts/RenderScopes.cs | 23 -------------------
2 files changed, 7 insertions(+), 28 deletions(-)
delete mode 100644 Dalamud/Interface/Internal/Asserts/RenderScopes.cs
diff --git a/Dalamud.Boot/Dalamud.Boot.vcxproj b/Dalamud.Boot/Dalamud.Boot.vcxproj
index 80435cd67..c18045027 100644
--- a/Dalamud.Boot/Dalamud.Boot.vcxproj
+++ b/Dalamud.Boot/Dalamud.Boot.vcxproj
@@ -28,7 +28,7 @@
v143
false
Unicode
- ..\bin\$(Configuration)\
+ bin\$(Configuration)\
obj\$(Configuration)\
@@ -200,8 +200,10 @@
-
-
-
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/Dalamud/Interface/Internal/Asserts/RenderScopes.cs b/Dalamud/Interface/Internal/Asserts/RenderScopes.cs
deleted file mode 100644
index 1e0448e87..000000000
--- a/Dalamud/Interface/Internal/Asserts/RenderScopes.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System.Diagnostics;
-
-namespace Dalamud.Interface.Internal.Asserts;
-
-public static class RenderScopes
-{
- private static RenderScopeFrame currentFrame = new();
- private static RenderScopeFrame lastFrame = new();
-
- public static RenderScopeFrame GetLastFrame() => lastFrame;
-
- public static RenderScopeFrame GetCurrentFrame() => currentFrame;
-
- public static void NewFrame()
- {
- //Debug.Assert(currentFrame.IsRoot, "NewFrame() but we didn't pop all the way to .");
- }
-
- public class RenderScopeFrame
- {
-
- }
-}
From d200c12c2f40c012c1e7283ab1b1ec39b30d16e8 Mon Sep 17 00:00:00 2001
From: goat
Date: Sat, 28 Dec 2024 14:02:06 +0100
Subject: [PATCH 41/88] copy cimgui DLLs in their vcxproj instead of Dalamud
---
Dalamud/Dalamud.csproj | 14 --------------
external/cimgui/cimgui.vcxproj | 9 +++++++--
external/cimguizmo/cimguizmo.vcxproj | 9 +++++++--
external/cimplot/cimplot.vcxproj | 9 +++++++--
4 files changed, 21 insertions(+), 20 deletions(-)
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index 1cd9fc336..d869f76ba 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -205,18 +205,4 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/external/cimgui/cimgui.vcxproj b/external/cimgui/cimgui.vcxproj
index a7a7ddb0e..55e737595 100644
--- a/external/cimgui/cimgui.vcxproj
+++ b/external/cimgui/cimgui.vcxproj
@@ -56,7 +56,8 @@
- ..\$(Platform)\$(Configuration)\
+ bin\$(Configuration)\
+ obj\$(Configuration)\
@@ -99,4 +100,8 @@
-
\ No newline at end of file
+
+
+
+
+
diff --git a/external/cimguizmo/cimguizmo.vcxproj b/external/cimguizmo/cimguizmo.vcxproj
index 48b432327..3014786b8 100644
--- a/external/cimguizmo/cimguizmo.vcxproj
+++ b/external/cimguizmo/cimguizmo.vcxproj
@@ -60,7 +60,8 @@
- ..\$(Platform)\$(Configuration)\
+ bin\$(Configuration)\
+ obj\$(Configuration)\
@@ -105,4 +106,8 @@
-
\ No newline at end of file
+
+
+
+
+
diff --git a/external/cimplot/cimplot.vcxproj b/external/cimplot/cimplot.vcxproj
index c7ae46a6b..c2b468fab 100644
--- a/external/cimplot/cimplot.vcxproj
+++ b/external/cimplot/cimplot.vcxproj
@@ -58,7 +58,8 @@
- ..\$(Platform)\$(Configuration)\
+ bin\$(Configuration)\
+ obj\$(Configuration)\
@@ -103,4 +104,8 @@
-
\ No newline at end of file
+
+
+
+
+
From 01980c3133a3486acacbd80262fa7a1fb672aadc Mon Sep 17 00:00:00 2001
From: goat
Date: Sun, 29 Dec 2024 12:42:43 +0100
Subject: [PATCH 42/88] plugin installer: add linebreak after ban reason
---
.../PluginInstaller/PluginInstallerWindow.cs | 108 +++++++++---------
1 file changed, 54 insertions(+), 54 deletions(-)
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
index 61f4bd1fc..4daccab3b 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
@@ -120,7 +120,7 @@ internal class PluginInstallerWindow : Window, IDisposable
private List pluginListUpdatable = new();
private bool hasDevPlugins = false;
private bool hasHiddenPlugins = false;
-
+
private string searchText = string.Empty;
private bool isSearchTextPrefilled = false;
@@ -137,7 +137,7 @@ internal class PluginInstallerWindow : Window, IDisposable
private LoadingIndicatorKind loadingIndicatorKind = LoadingIndicatorKind.Unknown;
private string verifiedCheckmarkHoveredPlugin = string.Empty;
-
+
private string? staleDalamudNewVersion = null;
///
@@ -215,8 +215,8 @@ internal class PluginInstallerWindow : Window, IDisposable
ProfileOrNot,
SearchScore,
}
-
- [Flags]
+
+ [Flags]
private enum PluginHeaderFlags
{
None = 0,
@@ -236,7 +236,7 @@ internal class PluginInstallerWindow : Window, IDisposable
Updateable,
Dev,
}
-
+
private bool AnyOperationInProgress => this.installStatus == OperationStatus.InProgress ||
this.updateStatus == OperationStatus.InProgress ||
this.enableDisableStatus == OperationStatus.InProgress;
@@ -304,7 +304,7 @@ internal class PluginInstallerWindow : Window, IDisposable
{
if (!t.IsCompletedSuccessfully)
return;
-
+
var versionInfo = t.Result;
if (versionInfo.AssemblyVersion != Util.GetScmVersion() &&
versionInfo.Track != "release" &&
@@ -413,7 +413,7 @@ internal class PluginInstallerWindow : Window, IDisposable
{
if (!task.IsFaulted && !task.IsCanceled)
return true;
-
+
var newErrorMessage = state as string;
if (task.Exception != null)
@@ -438,7 +438,7 @@ internal class PluginInstallerWindow : Window, IDisposable
}
}
}
-
+
if (task.IsCanceled)
Log.Error("A task was cancelled");
@@ -446,14 +446,14 @@ internal class PluginInstallerWindow : Window, IDisposable
return false;
}
-
+
private static void EnsureHaveTestingOptIn(IPluginManifest manifest)
{
var configuration = Service.Get();
-
+
if (configuration.PluginTestingOptIns.Any(x => x.InternalName == manifest.InternalName))
return;
-
+
configuration.PluginTestingOptIns.Add(new PluginTestingOptIn(manifest.InternalName));
configuration.QueueSave();
}
@@ -490,7 +490,7 @@ internal class PluginInstallerWindow : Window, IDisposable
throw new ArgumentOutOfRangeException(nameof(kind), kind, null);
}
}
-
+
private void DrawProgressOverlay()
{
var pluginManager = Service.Get();
@@ -733,7 +733,7 @@ internal class PluginInstallerWindow : Window, IDisposable
}
}
}
-
+
private void DrawFooter()
{
var configuration = Service.Get();
@@ -802,7 +802,7 @@ internal class PluginInstallerWindow : Window, IDisposable
{
this.updateStatus = OperationStatus.InProgress;
this.loadingIndicatorKind = LoadingIndicatorKind.UpdatingAll;
-
+
var toUpdate = this.pluginListUpdatable
.Where(x => x.InstalledPlugin.IsWantedByAnyProfile)
.ToList();
@@ -994,7 +994,7 @@ internal class PluginInstallerWindow : Window, IDisposable
ImGui.Text(Locs.DeletePluginConfigWarningModal_ExplainTesting());
ImGui.PopStyleColor();
}
-
+
ImGui.Text(Locs.DeletePluginConfigWarningModal_Body(this.deletePluginConfigWarningModalPluginName));
ImGui.Spacing();
@@ -1264,7 +1264,7 @@ internal class PluginInstallerWindow : Window, IDisposable
plugin.Manifest.RepoUrl == availableManifest.RepoUrl &&
!plugin.IsDev);
- // We "consumed" this plugin from the pile and remove it.
+ // We "consumed" this plugin from the pile and remove it.
if (plugin != null)
{
installedPlugins.Remove(plugin);
@@ -1296,7 +1296,7 @@ internal class PluginInstallerWindow : Window, IDisposable
return isHidden;
return !isHidden;
}
-
+
// Filter out plugins that are not hidden
proxies = proxies.Where(IsProxyHidden).ToList();
@@ -1328,14 +1328,14 @@ internal class PluginInstallerWindow : Window, IDisposable
ImGui.PopID();
}
-
+
// Reset the category to "All" if we're on the "Hidden" category and there are no hidden plugins (we removed the last one)
if (i == 0 && this.categoryManager.CurrentCategoryKind == PluginCategoryManager.CategoryKind.Hidden)
{
this.categoryManager.CurrentCategoryKind = PluginCategoryManager.CategoryKind.All;
}
}
-
+
private void DrawInstalledPluginList(InstalledPluginListFilter filter)
{
var pluginList = this.pluginListInstalled;
@@ -1363,7 +1363,7 @@ internal class PluginInstallerWindow : Window, IDisposable
{
if (filter == InstalledPluginListFilter.Testing && !manager.HasTestingOptIn(plugin.Manifest))
continue;
-
+
// Find applicable update and manifest, if we have them
AvailablePluginUpdate? update = null;
RemotePluginManifest? remoteManifest = null;
@@ -1383,11 +1383,11 @@ internal class PluginInstallerWindow : Window, IDisposable
{
continue;
}
-
+
this.DrawInstalledPlugin(plugin, i++, remoteManifest, update);
drewAny = true;
}
-
+
if (!drewAny)
{
var text = filter switch
@@ -1398,7 +1398,7 @@ internal class PluginInstallerWindow : Window, IDisposable
InstalledPluginListFilter.Dev => Locs.TabBody_NoPluginsDev,
_ => throw new ArgumentException(null, nameof(filter)),
};
-
+
ImGuiHelpers.ScaledDummy(60);
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudGrey))
@@ -1490,7 +1490,7 @@ internal class PluginInstallerWindow : Window, IDisposable
foreach (var categoryKind in groupInfo.Categories)
{
var categoryInfo = this.categoryManager.CategoryList.First(x => x.CategoryKind == categoryKind);
-
+
switch (categoryInfo.Condition)
{
case PluginCategoryManager.CategoryInfo.AppearCondition.None:
@@ -1549,7 +1549,7 @@ internal class PluginInstallerWindow : Window, IDisposable
ImGui.PopFont();
ImGui.PopStyleColor();
}
-
+
void DrawLinesCentered(string text)
{
var lines = text.Split('\n');
@@ -1558,7 +1558,7 @@ internal class PluginInstallerWindow : Window, IDisposable
ImGuiHelpers.CenteredText(line);
}
}
-
+
var pm = Service.Get();
if (pm.SafeMode)
{
@@ -1623,7 +1623,7 @@ internal class PluginInstallerWindow : Window, IDisposable
case PluginCategoryManager.CategoryKind.IsTesting:
this.DrawInstalledPluginList(InstalledPluginListFilter.Testing);
break;
-
+
case PluginCategoryManager.CategoryKind.UpdateablePlugins:
this.DrawInstalledPluginList(InstalledPluginListFilter.Updateable);
break;
@@ -1631,7 +1631,7 @@ internal class PluginInstallerWindow : Window, IDisposable
case PluginCategoryManager.CategoryKind.PluginProfiles:
this.profileManagerWidget.Draw();
break;
-
+
default:
ImGui.TextUnformatted("You found a secret category. Please feel a sense of pride and accomplishment.");
break;
@@ -1652,7 +1652,7 @@ internal class PluginInstallerWindow : Window, IDisposable
case PluginCategoryManager.CategoryKind.PluginChangelogs:
this.DrawChangelogList(false, true);
break;
-
+
default:
ImGui.TextUnformatted("You found a quiet category. Please don't wake it up.");
break;
@@ -1979,9 +1979,9 @@ internal class PluginInstallerWindow : Window, IDisposable
var sectionSize = ImGuiHelpers.GlobalScale * 66;
var tapeCursor = ImGui.GetCursorPos();
-
+
ImGui.Separator();
-
+
var startCursor = ImGui.GetCursorPos();
if (flags.HasFlag(PluginHeaderFlags.IsTesting))
@@ -1992,9 +1992,9 @@ internal class PluginInstallerWindow : Window, IDisposable
var windowPos = ImGui.GetWindowPos();
var scroll = new Vector2(ImGui.GetScrollX(), ImGui.GetScrollY());
-
+
var adjustedPosition = windowPos + position - scroll;
-
+
var yellow = ImGui.ColorConvertFloat4ToU32(new Vector4(1.0f, 0.9f, 0.0f, 0.10f));
var numStripes = (int)(size.X / stripeWidth) + (int)(size.Y / skewAmount) + 1; // +1 to cover partial stripe
@@ -2004,19 +2004,19 @@ internal class PluginInstallerWindow : Window, IDisposable
var x1 = x0 + stripeWidth;
var y0 = adjustedPosition.Y;
var y1 = y0 + size.Y;
-
+
var p0 = new Vector2(x0, y0);
var p1 = new Vector2(x1, y0);
var p2 = new Vector2(x1 - skewAmount, y1);
var p3 = new Vector2(x0 - skewAmount, y1);
-
+
if (i % 2 != 0)
continue;
-
+
wdl.AddQuadFilled(p0, p1, p2, p3, yellow);
}
}
-
+
DrawCautionTape(tapeCursor + new Vector2(0, 1), new Vector2(ImGui.GetWindowWidth(), sectionSize + ImGui.GetStyle().ItemSpacing.Y), ImGuiHelpers.GlobalScale * 40, 20);
}
@@ -2025,7 +2025,7 @@ internal class PluginInstallerWindow : Window, IDisposable
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(0.5f, 0.5f, 0.5f, 0.2f));
ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(0.5f, 0.5f, 0.5f, 0.35f));
ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 0);
-
+
ImGui.SetCursorPos(tapeCursor);
if (ImGui.Button($"###plugin{index}CollapsibleBtn", new Vector2(ImGui.GetContentRegionAvail().X, sectionSize + ImGui.GetStyle().ItemSpacing.Y)))
@@ -2194,7 +2194,7 @@ internal class PluginInstallerWindow : Window, IDisposable
bodyText += " ";
if (flags.HasFlag(PluginHeaderFlags.UpdateAvailable))
- bodyText += Locs.PluginBody_Outdated_CanNowUpdate;
+ bodyText += "\n" + Locs.PluginBody_Outdated_CanNowUpdate;
else
bodyText += Locs.PluginBody_Outdated_WaitForUpdate;
@@ -2368,11 +2368,11 @@ internal class PluginInstallerWindow : Window, IDisposable
{
label += Locs.PluginTitleMod_TestingAvailable;
}
-
+
var isThirdParty = manifest.SourceRepo.IsThirdParty;
ImGui.PushID($"available{index}{manifest.InternalName}");
-
+
var flags = PluginHeaderFlags.None;
if (isThirdParty)
flags |= PluginHeaderFlags.IsThirdParty;
@@ -2382,7 +2382,7 @@ internal class PluginInstallerWindow : Window, IDisposable
flags |= PluginHeaderFlags.IsInstallableOutdated;
if (useTesting || manifest.IsTestingExclusive)
flags |= PluginHeaderFlags.IsTesting;
-
+
if (this.DrawPluginCollapsingHeader(label, null, manifest, flags, () => this.DrawAvailablePluginContextMenu(manifest), index))
{
if (!wasSeen)
@@ -2478,7 +2478,7 @@ internal class PluginInstallerWindow : Window, IDisposable
EnsureHaveTestingOptIn(manifest);
this.StartInstall(manifest, true);
}
-
+
ImGui.Separator();
}
@@ -2676,9 +2676,9 @@ internal class PluginInstallerWindow : Window, IDisposable
availablePluginUpdate.UseTesting ?
availablePluginUpdate.UpdateManifest.TestingAssemblyVersion :
availablePluginUpdate.UpdateManifest.AssemblyVersion;
-
+
availableChangelog =
- availablePluginUpdate.UseTesting ?
+ availablePluginUpdate.UseTesting ?
availablePluginUpdate.UpdateManifest.TestingChangelog :
availablePluginUpdate.UpdateManifest.Changelog;
}
@@ -2835,7 +2835,7 @@ internal class PluginInstallerWindow : Window, IDisposable
{
this.DrawInstalledPluginChangelog(applicableChangelog);
}
-
+
if (this.categoryManager.CurrentCategoryKind == PluginCategoryManager.CategoryKind.UpdateablePlugins &&
!availableChangelog.IsNullOrWhitespace() &&
!didDrawAvailableChangelogInsideCollapsible)
@@ -3689,7 +3689,7 @@ internal class PluginInstallerWindow : Window, IDisposable
this.pluginListUpdatable = pluginManager.UpdatablePlugins.ToList();
this.ResortPlugins();
}
-
+
this.hasHiddenPlugins = this.pluginListAvailable.Any(x => configuration.HiddenPluginInternalName.Contains(x.InternalName));
this.UpdateCategoriesOnPluginsChange();
@@ -3943,16 +3943,16 @@ internal class PluginInstallerWindow : Window, IDisposable
public static string TabBody_DownloadFailed => Loc.Localize("InstallerDownloadFailed", "Download failed.");
public static string TabBody_SafeMode => Loc.Localize("InstallerSafeMode", "Dalamud is running in Plugin Safe Mode, restart to activate plugins.");
-
+
public static string TabBody_NoPluginsTesting => Loc.Localize("InstallerNoPluginsTesting", "You aren't testing any plugins at the moment!\nYou can opt in to testing versions in the plugin context menu.");
-
+
public static string TabBody_NoPluginsInstalled =>
string.Format(Loc.Localize("InstallerNoPluginsInstalled", "You don't have any plugins installed yet!\nYou can install them from the \"{0}\" tab."), PluginCategoryManager.Locs.Category_All);
-
+
public static string TabBody_NoPluginsUpdateable => Loc.Localize("InstallerNoPluginsUpdate", "No plugins have updates available at the moment.");
-
+
public static string TabBody_NoPluginsDev => Loc.Localize("InstallerNoPluginsDev", "You don't have any dev plugins. Add them from the settings.");
-
+
#endregion
#region Search text
@@ -4014,11 +4014,11 @@ internal class PluginInstallerWindow : Window, IDisposable
public static string PluginContext_TestingOptIn => Loc.Localize("InstallerTestingOptIn", "Receive plugin testing versions");
public static string PluginContext_InstallTestingVersion => Loc.Localize("InstallerInstallTestingVersion", "Install testing version");
-
+
public static string PluginContext_MarkAllSeen => Loc.Localize("InstallerMarkAllSeen", "Mark all as seen");
public static string PluginContext_HidePlugin => Loc.Localize("InstallerHidePlugin", "Hide from installer");
-
+
public static string PluginContext_UnhidePlugin => Loc.Localize("InstallerUnhidePlugin", "Unhide from installer");
public static string PluginContext_DeletePluginConfig => Loc.Localize("InstallerDeletePluginConfig", "Reset plugin data");
From c79b1cd83a22c114ab592db4d0ba2d38866c22a9 Mon Sep 17 00:00:00 2001
From: goat
Date: Sun, 29 Dec 2024 13:17:03 +0100
Subject: [PATCH 43/88] config: save asynchronously to prevent hitches
---
.../Internal/DalamudConfiguration.cs | 24 ++++-
.../Internal/Windows/Data/DataWindow.cs | 1 +
.../Windows/Data/Widgets/VfsWidget.cs | 102 ++++++++++++++++++
3 files changed, 125 insertions(+), 2 deletions(-)
create mode 100644 Dalamud/Interface/Internal/Windows/Data/Widgets/VfsWidget.cs
diff --git a/Dalamud/Configuration/Internal/DalamudConfiguration.cs b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
index 22fb2f448..850aeb7e9 100644
--- a/Dalamud/Configuration/Internal/DalamudConfiguration.cs
+++ b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
@@ -4,6 +4,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
+using System.Threading.Tasks;
using Dalamud.Game.Text;
using Dalamud.Interface;
@@ -45,6 +46,8 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
[JsonIgnore]
private bool isSaveQueued;
+ private Task? writeTask;
+
///
/// Delegate for the event that occurs when the dalamud configuration is saved.
///
@@ -560,6 +563,9 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
{
// Make sure that we save, if a save is queued while we are shutting down
this.Update();
+
+ // Wait for the write task to finish
+ this.writeTask?.Wait();
}
///
@@ -614,8 +620,22 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
if (this.configPath is null)
throw new InvalidOperationException("configPath is not set.");
- Service.Get().WriteAllText(
- this.configPath, JsonConvert.SerializeObject(this, SerializerSettings));
+ // Wait for previous write to finish
+ this.writeTask?.Wait();
+
+ this.writeTask = Task.Run(() =>
+ {
+ Service.Get().WriteAllText(
+ this.configPath,
+ JsonConvert.SerializeObject(this, SerializerSettings));
+ }).ContinueWith(t =>
+ {
+ if (t.IsFaulted)
+ {
+ Log.Error(t.Exception, "Failed to save DalamudConfiguration to {Path}", this.configPath);
+ }
+ });
+
this.DalamudConfigurationSaved?.Invoke(this);
}
}
diff --git a/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs b/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs
index 7678b395e..f3ec882fc 100644
--- a/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs
@@ -60,6 +60,7 @@ internal class DataWindow : Window, IDisposable
new ToastWidget(),
new UiColorWidget(),
new UldWidget(),
+ new VfsWidget(),
};
private readonly IOrderedEnumerable orderedModules;
diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/VfsWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/VfsWidget.cs
new file mode 100644
index 000000000..019d743bc
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/VfsWidget.cs
@@ -0,0 +1,102 @@
+using System.Diagnostics;
+using System.IO;
+
+using Dalamud.Configuration.Internal;
+using Dalamud.Storage;
+using ImGuiNET;
+using Serilog;
+
+namespace Dalamud.Interface.Internal.Windows.Data.Widgets;
+
+///
+/// Widget for displaying configuration info.
+///
+internal class VfsWidget : IDataWindowWidget
+{
+ private int numBytes = 1024;
+ private int reps = 1;
+
+ ///
+ public string[]? CommandShortcuts { get; init; } = { "vfs" };
+
+ ///
+ public string DisplayName { get; init; } = "VFS Performance";
+
+ ///
+ public bool Ready { get; set; }
+
+ ///
+ public void Load()
+ {
+ this.Ready = true;
+ }
+
+ ///
+ public void Draw()
+ {
+ var service = Service.Get();
+ var dalamud = Service.Get();
+
+ ImGui.InputInt("Num bytes", ref this.numBytes);
+ ImGui.InputInt("Reps", ref this.reps);
+
+ var path = Path.Combine(dalamud.StartInfo.WorkingDirectory!, "test.bin");
+
+ if (ImGui.Button("Write"))
+ {
+ Log.Information("=== WRITING ===");
+ var data = new byte[this.numBytes];
+ var stopwatch = new Stopwatch();
+ var acc = 0L;
+
+ for (var i = 0; i < this.reps; i++)
+ {
+ stopwatch.Restart();
+ service.WriteAllBytes(path, data);
+ stopwatch.Stop();
+ acc += stopwatch.ElapsedMilliseconds;
+ Log.Information("Turn {Turn} took {Ms}ms", i, stopwatch.ElapsedMilliseconds);
+ }
+
+ Log.Information("Took {Ms}ms in total", acc);
+ }
+
+ if (ImGui.Button("Read"))
+ {
+ Log.Information("=== READING ===");
+ var stopwatch = new Stopwatch();
+ var acc = 0L;
+
+ for (var i = 0; i < this.reps; i++)
+ {
+ stopwatch.Restart();
+ service.ReadAllBytes(path);
+ stopwatch.Stop();
+ acc += stopwatch.ElapsedMilliseconds;
+ Log.Information("Turn {Turn} took {Ms}ms", i, stopwatch.ElapsedMilliseconds);
+ }
+
+ Log.Information("Took {Ms}ms in total", acc);
+ }
+
+ if (ImGui.Button("Test Config"))
+ {
+ var config = Service.Get();
+
+ Log.Information("=== READING ===");
+ var stopwatch = new Stopwatch();
+ var acc = 0L;
+
+ for (var i = 0; i < this.reps; i++)
+ {
+ stopwatch.Restart();
+ config.ForceSave();
+ stopwatch.Stop();
+ acc += stopwatch.ElapsedMilliseconds;
+ Log.Information("Turn {Turn} took {Ms}ms", i, stopwatch.ElapsedMilliseconds);
+ }
+
+ Log.Information("Took {Ms}ms in total", acc);
+ }
+ }
+}
From 2e77e905322a568017001c5dd531f65d346ba43f Mon Sep 17 00:00:00 2001
From: goat
Date: Sun, 29 Dec 2024 13:49:31 +0100
Subject: [PATCH 44/88] title screen menu: some visual fixes Use
SeStringRenderer to render menu entries Clamp alpha values to avoid
flickering
---
.../Internal/Windows/TitleScreenMenuWindow.cs | 36 ++++++++-----------
1 file changed, 15 insertions(+), 21 deletions(-)
diff --git a/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs b/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs
index 88f291954..979f68bf8 100644
--- a/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs
@@ -11,6 +11,7 @@ using Dalamud.Game.ClientState;
using Dalamud.Game.Gui;
using Dalamud.Game.Text;
using Dalamud.Interface.Animation.EasingFunctions;
+using Dalamud.Interface.ImGuiSeStringRenderer;
using Dalamud.Interface.ManagedFontAtlas;
using Dalamud.Interface.ManagedFontAtlas.Internals;
using Dalamud.Interface.Textures.TextureWraps;
@@ -50,11 +51,11 @@ internal class TitleScreenMenuWindow : Window, IDisposable
private readonly Lazy myFontHandle;
private readonly Lazy shadeTexture;
private readonly AddonLifecycleEventListener versionStringListener;
-
+
private readonly Dictionary shadeEasings = new();
private readonly Dictionary moveEasings = new();
private readonly Dictionary logoEasings = new();
-
+
private readonly IConsoleVariable showTsm;
private InOutCubic? fadeOutEasing;
@@ -62,7 +63,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
private State state = State.Hide;
private int lastLoadedPluginCount = -1;
-
+
///
/// Initializes a new instance of the class.
///
@@ -91,7 +92,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
ImGuiWindowFlags.NoBackground | ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.NoNavFocus)
{
this.showTsm = consoleManager.AddVariable("dalamud.show_tsm", "Show the Title Screen Menu", true);
-
+
this.clientState = clientState;
this.configuration = configuration;
this.gameGui = gameGui;
@@ -124,7 +125,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
framework.Update += this.FrameworkOnUpdate;
this.scopedFinalizer.Add(() => framework.Update -= this.FrameworkOnUpdate);
-
+
this.versionStringListener = new AddonLifecycleEventListener(AddonEvent.PreDraw, "_TitleRevision", this.OnVersionStringDraw);
addonLifecycle.RegisterListener(this.versionStringListener);
this.scopedFinalizer.Add(() => addonLifecycle.UnregisterListener(this.versionStringListener));
@@ -136,7 +137,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
Show,
FadeOut,
}
-
+
///
/// Gets or sets a value indicating whether drawing is allowed.
///
@@ -165,7 +166,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
{
if (!this.AllowDrawing || !this.showTsm.Value)
return;
-
+
var scale = ImGui.GetIO().FontGlobalScale;
var entries = this.titleScreenMenu.PluginEntries;
@@ -174,7 +175,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
ImGuiHoveredFlags.AllowWhenBlockedByActiveItem);
Service.Get().OverrideGameCursor = !hovered;
-
+
switch (this.state)
{
case State.Show:
@@ -251,7 +252,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
this.fadeOutEasing.Update();
- using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)this.fadeOutEasing.Value))
+ using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)Math.Max(this.fadeOutEasing.Value, 0)))
{
var i = 0;
foreach (var entry in entries)
@@ -392,21 +393,14 @@ internal class TitleScreenMenuWindow : Window, IDisposable
if (overrideAlpha)
{
- ImGui.PushStyleVar(ImGuiStyleVar.Alpha, showText ? (float)logoEasing.Value : 0f);
+ ImGui.PushStyleVar(ImGuiStyleVar.Alpha, showText ? (float)Math.Min(logoEasing.Value, 1) : 0f);
}
// Drop shadow
- using (ImRaii.PushColor(ImGuiCol.Text, 0xFF000000))
- {
- for (int i = 0, to = (int)Math.Ceiling(1 * scale); i < to; i++)
- {
- ImGui.SetCursorPos(new Vector2(cursor.X, cursor.Y + i));
- ImGui.Text(entry.Name);
- }
- }
-
ImGui.SetCursorPos(cursor);
- ImGui.Text(entry.Name);
+ var renderStyle = default(SeStringDrawParams);
+ renderStyle.FontSize = TargetFontSizePx;
+ ImGuiHelpers.CompileSeStringWrapped($"{entry.Name}", renderStyle);
if (overrideAlpha)
{
@@ -439,7 +433,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
var addon = (AtkUnitBase*)drawArgs.Addon;
var textNode = addon->GetTextNodeById(3);
-
+
// look and feel init. should be harmless to set.
textNode->TextFlags |= (byte)TextFlags.MultiLine;
textNode->AlignmentType = AlignmentType.TopLeft;
From 1aada983931d9e45a250eebbc17c8b782d07701b Mon Sep 17 00:00:00 2001
From: goat
Date: Sun, 29 Dec 2024 16:53:16 +0100
Subject: [PATCH 45/88] clamp value of all easings by default
---
Dalamud/Interface/Animation/Easing.cs | 10 ++++++++--
.../Interface/Animation/EasingFunctions/InCirc.cs | 2 +-
.../Interface/Animation/EasingFunctions/InCubic.cs | 2 +-
.../Animation/EasingFunctions/InElastic.cs | 10 +++++-----
.../Animation/EasingFunctions/InOutCirc.cs | 6 +++---
.../Animation/EasingFunctions/InOutCubic.cs | 2 +-
.../Animation/EasingFunctions/InOutElastic.cs | 14 +++++++-------
.../Animation/EasingFunctions/InOutQuint.cs | 2 +-
.../Animation/EasingFunctions/InOutSine.cs | 2 +-
.../Interface/Animation/EasingFunctions/InQuint.cs | 2 +-
.../Interface/Animation/EasingFunctions/InSine.cs | 2 +-
.../Interface/Animation/EasingFunctions/OutCirc.cs | 2 +-
.../Animation/EasingFunctions/OutCubic.cs | 2 +-
.../Animation/EasingFunctions/OutElastic.cs | 10 +++++-----
.../Animation/EasingFunctions/OutQuint.cs | 2 +-
.../Interface/Animation/EasingFunctions/OutSine.cs | 2 +-
.../Internal/Windows/TitleScreenMenuWindow.cs | 4 ++--
17 files changed, 41 insertions(+), 35 deletions(-)
diff --git a/Dalamud/Interface/Animation/Easing.cs b/Dalamud/Interface/Animation/Easing.cs
index edab25149..a48300a22 100644
--- a/Dalamud/Interface/Animation/Easing.cs
+++ b/Dalamud/Interface/Animation/Easing.cs
@@ -43,9 +43,15 @@ public abstract class Easing
public bool IsInverse { get; set; }
///
- /// Gets or sets the current value of the animation, from 0 to 1.
+ /// Gets the current value of the animation, from 0 to 1.
///
- public double Value
+ public double Value => Math.Clamp(this.ValueUnclamped, 0, 1);
+
+ ///
+ /// Gets or sets the current value of the animation, not limited to a range of 0 to 1.
+ /// Will return numbers outside of this range if accessed beyond animation time.
+ ///
+ public double ValueUnclamped
{
get
{
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InCirc.cs b/Dalamud/Interface/Animation/EasingFunctions/InCirc.cs
index c467104c5..d94e9fc9f 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InCirc.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InCirc.cs
@@ -19,6 +19,6 @@ public class InCirc : Easing
public override void Update()
{
var p = this.Progress;
- this.Value = 1 - Math.Sqrt(1 - Math.Pow(p, 2));
+ this.ValueUnclamped = 1 - Math.Sqrt(1 - Math.Pow(p, 2));
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InCubic.cs b/Dalamud/Interface/Animation/EasingFunctions/InCubic.cs
index 78f6774ac..64ebc5ba3 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InCubic.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InCubic.cs
@@ -19,6 +19,6 @@ public class InCubic : Easing
public override void Update()
{
var p = this.Progress;
- this.Value = p * p * p;
+ this.ValueUnclamped = p * p * p;
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InElastic.cs b/Dalamud/Interface/Animation/EasingFunctions/InElastic.cs
index c53c3d587..2e834e41c 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InElastic.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InElastic.cs
@@ -21,10 +21,10 @@ public class InElastic : Easing
public override void Update()
{
var p = this.Progress;
- this.Value = p == 0
- ? 0
- : p == 1
- ? 1
- : -Math.Pow(2, (10 * p) - 10) * Math.Sin(((p * 10) - 10.75) * Constant);
+ this.ValueUnclamped = p == 0
+ ? 0
+ : p == 1
+ ? 1
+ : -Math.Pow(2, (10 * p) - 10) * Math.Sin(((p * 10) - 10.75) * Constant);
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InOutCirc.cs b/Dalamud/Interface/Animation/EasingFunctions/InOutCirc.cs
index 71a598dfb..a63ab648a 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InOutCirc.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InOutCirc.cs
@@ -19,8 +19,8 @@ public class InOutCirc : Easing
public override void Update()
{
var p = this.Progress;
- this.Value = p < 0.5
- ? (1 - Math.Sqrt(1 - Math.Pow(2 * p, 2))) / 2
- : (Math.Sqrt(1 - Math.Pow((-2 * p) + 2, 2)) + 1) / 2;
+ this.ValueUnclamped = p < 0.5
+ ? (1 - Math.Sqrt(1 - Math.Pow(2 * p, 2))) / 2
+ : (Math.Sqrt(1 - Math.Pow((-2 * p) + 2, 2)) + 1) / 2;
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InOutCubic.cs b/Dalamud/Interface/Animation/EasingFunctions/InOutCubic.cs
index 07bcfa28d..4083265b7 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InOutCubic.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InOutCubic.cs
@@ -19,6 +19,6 @@ public class InOutCubic : Easing
public override void Update()
{
var p = this.Progress;
- this.Value = p < 0.5 ? 4 * p * p * p : 1 - (Math.Pow((-2 * p) + 2, 3) / 2);
+ this.ValueUnclamped = p < 0.5 ? 4 * p * p * p : 1 - (Math.Pow((-2 * p) + 2, 3) / 2);
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InOutElastic.cs b/Dalamud/Interface/Animation/EasingFunctions/InOutElastic.cs
index f78f9f336..f27726038 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InOutElastic.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InOutElastic.cs
@@ -21,12 +21,12 @@ public class InOutElastic : Easing
public override void Update()
{
var p = this.Progress;
- this.Value = p == 0
- ? 0
- : p == 1
- ? 1
- : p < 0.5
- ? -(Math.Pow(2, (20 * p) - 10) * Math.Sin(((20 * p) - 11.125) * Constant)) / 2
- : (Math.Pow(2, (-20 * p) + 10) * Math.Sin(((20 * p) - 11.125) * Constant) / 2) + 1;
+ this.ValueUnclamped = p == 0
+ ? 0
+ : p == 1
+ ? 1
+ : p < 0.5
+ ? -(Math.Pow(2, (20 * p) - 10) * Math.Sin(((20 * p) - 11.125) * Constant)) / 2
+ : (Math.Pow(2, (-20 * p) + 10) * Math.Sin(((20 * p) - 11.125) * Constant) / 2) + 1;
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InOutQuint.cs b/Dalamud/Interface/Animation/EasingFunctions/InOutQuint.cs
index 64ab98b16..e08129b25 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InOutQuint.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InOutQuint.cs
@@ -19,6 +19,6 @@ public class InOutQuint : Easing
public override void Update()
{
var p = this.Progress;
- this.Value = p < 0.5 ? 16 * p * p * p * p * p : 1 - (Math.Pow((-2 * p) + 2, 5) / 2);
+ this.ValueUnclamped = p < 0.5 ? 16 * p * p * p * p * p : 1 - (Math.Pow((-2 * p) + 2, 5) / 2);
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InOutSine.cs b/Dalamud/Interface/Animation/EasingFunctions/InOutSine.cs
index 2f347ff80..cb940d87d 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InOutSine.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InOutSine.cs
@@ -19,6 +19,6 @@ public class InOutSine : Easing
public override void Update()
{
var p = this.Progress;
- this.Value = -(Math.Cos(Math.PI * p) - 1) / 2;
+ this.ValueUnclamped = -(Math.Cos(Math.PI * p) - 1) / 2;
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InQuint.cs b/Dalamud/Interface/Animation/EasingFunctions/InQuint.cs
index a5ab5a22c..827e0e21b 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InQuint.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InQuint.cs
@@ -19,6 +19,6 @@ public class InQuint : Easing
public override void Update()
{
var p = this.Progress;
- this.Value = p * p * p * p * p;
+ this.ValueUnclamped = p * p * p * p * p;
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InSine.cs b/Dalamud/Interface/Animation/EasingFunctions/InSine.cs
index fa079baad..61affa10a 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InSine.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InSine.cs
@@ -19,6 +19,6 @@ public class InSine : Easing
public override void Update()
{
var p = this.Progress;
- this.Value = 1 - Math.Cos((p * Math.PI) / 2);
+ this.ValueUnclamped = 1 - Math.Cos((p * Math.PI) / 2);
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/OutCirc.cs b/Dalamud/Interface/Animation/EasingFunctions/OutCirc.cs
index b0d3b895a..980e29a81 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/OutCirc.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/OutCirc.cs
@@ -19,6 +19,6 @@ public class OutCirc : Easing
public override void Update()
{
var p = this.Progress;
- this.Value = Math.Sqrt(1 - Math.Pow(p - 1, 2));
+ this.ValueUnclamped = Math.Sqrt(1 - Math.Pow(p - 1, 2));
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/OutCubic.cs b/Dalamud/Interface/Animation/EasingFunctions/OutCubic.cs
index 9c1bb57dc..e1a79c35b 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/OutCubic.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/OutCubic.cs
@@ -19,6 +19,6 @@ public class OutCubic : Easing
public override void Update()
{
var p = this.Progress;
- this.Value = 1 - Math.Pow(1 - p, 3);
+ this.ValueUnclamped = 1 - Math.Pow(1 - p, 3);
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/OutElastic.cs b/Dalamud/Interface/Animation/EasingFunctions/OutElastic.cs
index 6a4fcd6dc..1f525b404 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/OutElastic.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/OutElastic.cs
@@ -21,10 +21,10 @@ public class OutElastic : Easing
public override void Update()
{
var p = this.Progress;
- this.Value = p == 0
- ? 0
- : p == 1
- ? 1
- : (Math.Pow(2, -10 * p) * Math.Sin(((p * 10) - 0.75) * Constant)) + 1;
+ this.ValueUnclamped = p == 0
+ ? 0
+ : p == 1
+ ? 1
+ : (Math.Pow(2, -10 * p) * Math.Sin(((p * 10) - 0.75) * Constant)) + 1;
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/OutQuint.cs b/Dalamud/Interface/Animation/EasingFunctions/OutQuint.cs
index a3174e762..24a2255d3 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/OutQuint.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/OutQuint.cs
@@ -19,6 +19,6 @@ public class OutQuint : Easing
public override void Update()
{
var p = this.Progress;
- this.Value = 1 - Math.Pow(1 - p, 5);
+ this.ValueUnclamped = 1 - Math.Pow(1 - p, 5);
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/OutSine.cs b/Dalamud/Interface/Animation/EasingFunctions/OutSine.cs
index ba82232b3..a376d7f57 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/OutSine.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/OutSine.cs
@@ -19,6 +19,6 @@ public class OutSine : Easing
public override void Update()
{
var p = this.Progress;
- this.Value = Math.Sin((p * Math.PI) / 2);
+ this.ValueUnclamped = Math.Sin((p * Math.PI) / 2);
}
}
diff --git a/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs b/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs
index 979f68bf8..c63efca64 100644
--- a/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs
@@ -252,7 +252,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
this.fadeOutEasing.Update();
- using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)Math.Max(this.fadeOutEasing.Value, 0)))
+ using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)this.fadeOutEasing.Value))
{
var i = 0;
foreach (var entry in entries)
@@ -393,7 +393,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
if (overrideAlpha)
{
- ImGui.PushStyleVar(ImGuiStyleVar.Alpha, showText ? (float)Math.Min(logoEasing.Value, 1) : 0f);
+ ImGui.PushStyleVar(ImGuiStyleVar.Alpha, showText ? (float)logoEasing.Value : 0f);
}
// Drop shadow
From 6dd85c9e3ee3643b3b408a4661f6c3ddb215420e Mon Sep 17 00:00:00 2001
From: goat
Date: Sun, 29 Dec 2024 16:56:31 +0100
Subject: [PATCH 46/88] remove some unused stuff in Util, fix warnings
---
Dalamud/Utility/Util.cs | 53 -----------------------------------------
1 file changed, 53 deletions(-)
diff --git a/Dalamud/Utility/Util.cs b/Dalamud/Utility/Util.cs
index d53828858..7724c68e0 100644
--- a/Dalamud/Utility/Util.cs
+++ b/Dalamud/Utility/Util.cs
@@ -65,7 +65,6 @@ public static class Util
private static readonly Type GenericSpanType = typeof(Span<>);
private static string? scmVersionInternal;
private static string? gitHashInternal;
- private static int? gitCommitCountInternal;
private static string? gitHashClientStructsInternal;
private static ulong moduleStartAddr;
@@ -77,58 +76,6 @@ public static class Util
public static string AssemblyVersion { get; } =
Assembly.GetAssembly(typeof(ChatHandlers)).GetName().Version.ToString();
- ///
- /// Check two byte arrays for equality.
- ///
- /// The first byte array.
- /// The second byte array.
- /// Whether or not the byte arrays are equal.
- public static unsafe bool FastByteArrayCompare(byte[]? a1, byte[]? a2)
- {
- // Copyright (c) 2008-2013 Hafthor Stefansson
- // Distributed under the MIT/X11 software license
- // Ref: http://www.opensource.org/licenses/mit-license.php.
- // https://stackoverflow.com/a/8808245
-
- if (a1 == a2) return true;
- if (a1 == null || a2 == null || a1.Length != a2.Length)
- return false;
- fixed (byte* p1 = a1, p2 = a2)
- {
- byte* x1 = p1, x2 = p2;
- var l = a1.Length;
- for (var i = 0; i < l / 8; i++, x1 += 8, x2 += 8)
- {
- if (*((long*)x1) != *((long*)x2))
- return false;
- }
-
- if ((l & 4) != 0)
- {
- if (*((int*)x1) != *((int*)x2))
- return false;
- x1 += 4;
- x2 += 4;
- }
-
- if ((l & 2) != 0)
- {
- if (*((short*)x1) != *((short*)x2))
- return false;
- x1 += 2;
- x2 += 2;
- }
-
- if ((l & 1) != 0)
- {
- if (*((byte*)x1) != *((byte*)x2))
- return false;
- }
-
- return true;
- }
- }
-
///
/// Gets the SCM Version from the assembly, or null if it cannot be found. This method will generally return
/// the git describe output for this build, which will be a raw version if this is a stable build or an
From 0cac90b03285b9654c8a45506acc419a8ff794b0 Mon Sep 17 00:00:00 2001
From: goat
Date: Sun, 29 Dec 2024 19:01:49 +0100
Subject: [PATCH 47/88] plugin installer: only allow feedback for non-outdated
plugins
---
.../Windows/PluginInstaller/PluginInstallerWindow.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
index 4daccab3b..4e60d4be8 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
@@ -2444,7 +2444,7 @@ internal class PluginInstallerWindow : Window, IDisposable
ImGuiHelpers.ScaledDummy(3);
}
- if (!manifest.SourceRepo.IsThirdParty && manifest.AcceptsFeedback)
+ if (!manifest.SourceRepo.IsThirdParty && manifest.AcceptsFeedback && !isOutdated)
{
ImGui.SameLine();
this.DrawSendFeedbackButton(manifest, false, true);
@@ -2724,8 +2724,8 @@ internal class PluginInstallerWindow : Window, IDisposable
var canFeedback = !isThirdParty &&
!plugin.IsDev &&
!plugin.IsOrphaned &&
- (plugin.Manifest.DalamudApiLevel == PluginManager.DalamudApiLevel
- || plugin.Manifest.TestingDalamudApiLevel == PluginManager.DalamudApiLevel) &&
+ (plugin.Manifest.DalamudApiLevel == PluginManager.DalamudApiLevel ||
+ (plugin.Manifest.TestingDalamudApiLevel == PluginManager.DalamudApiLevel && hasTestingAvailable)) &&
acceptsFeedback &&
availablePluginUpdate == default;
From b36bdb2086ed27244c11e31cc17a3f7d62c76a30 Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 30 Dec 2024 13:59:59 +0100
Subject: [PATCH 48/88] Revert "clamp value of all easings by default"
This reverts commit 1aada983931d9e45a250eebbc17c8b782d07701b.
Breaks the API.
---
Dalamud/Interface/Animation/Easing.cs | 10 ++--------
.../Interface/Animation/EasingFunctions/InCirc.cs | 2 +-
.../Interface/Animation/EasingFunctions/InCubic.cs | 2 +-
.../Animation/EasingFunctions/InElastic.cs | 10 +++++-----
.../Animation/EasingFunctions/InOutCirc.cs | 6 +++---
.../Animation/EasingFunctions/InOutCubic.cs | 2 +-
.../Animation/EasingFunctions/InOutElastic.cs | 14 +++++++-------
.../Animation/EasingFunctions/InOutQuint.cs | 2 +-
.../Animation/EasingFunctions/InOutSine.cs | 2 +-
.../Interface/Animation/EasingFunctions/InQuint.cs | 2 +-
.../Interface/Animation/EasingFunctions/InSine.cs | 2 +-
.../Interface/Animation/EasingFunctions/OutCirc.cs | 2 +-
.../Animation/EasingFunctions/OutCubic.cs | 2 +-
.../Animation/EasingFunctions/OutElastic.cs | 10 +++++-----
.../Animation/EasingFunctions/OutQuint.cs | 2 +-
.../Interface/Animation/EasingFunctions/OutSine.cs | 2 +-
.../Internal/Windows/TitleScreenMenuWindow.cs | 4 ++--
17 files changed, 35 insertions(+), 41 deletions(-)
diff --git a/Dalamud/Interface/Animation/Easing.cs b/Dalamud/Interface/Animation/Easing.cs
index a48300a22..edab25149 100644
--- a/Dalamud/Interface/Animation/Easing.cs
+++ b/Dalamud/Interface/Animation/Easing.cs
@@ -43,15 +43,9 @@ public abstract class Easing
public bool IsInverse { get; set; }
///
- /// Gets the current value of the animation, from 0 to 1.
+ /// Gets or sets the current value of the animation, from 0 to 1.
///
- public double Value => Math.Clamp(this.ValueUnclamped, 0, 1);
-
- ///
- /// Gets or sets the current value of the animation, not limited to a range of 0 to 1.
- /// Will return numbers outside of this range if accessed beyond animation time.
- ///
- public double ValueUnclamped
+ public double Value
{
get
{
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InCirc.cs b/Dalamud/Interface/Animation/EasingFunctions/InCirc.cs
index d94e9fc9f..c467104c5 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InCirc.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InCirc.cs
@@ -19,6 +19,6 @@ public class InCirc : Easing
public override void Update()
{
var p = this.Progress;
- this.ValueUnclamped = 1 - Math.Sqrt(1 - Math.Pow(p, 2));
+ this.Value = 1 - Math.Sqrt(1 - Math.Pow(p, 2));
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InCubic.cs b/Dalamud/Interface/Animation/EasingFunctions/InCubic.cs
index 64ebc5ba3..78f6774ac 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InCubic.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InCubic.cs
@@ -19,6 +19,6 @@ public class InCubic : Easing
public override void Update()
{
var p = this.Progress;
- this.ValueUnclamped = p * p * p;
+ this.Value = p * p * p;
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InElastic.cs b/Dalamud/Interface/Animation/EasingFunctions/InElastic.cs
index 2e834e41c..c53c3d587 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InElastic.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InElastic.cs
@@ -21,10 +21,10 @@ public class InElastic : Easing
public override void Update()
{
var p = this.Progress;
- this.ValueUnclamped = p == 0
- ? 0
- : p == 1
- ? 1
- : -Math.Pow(2, (10 * p) - 10) * Math.Sin(((p * 10) - 10.75) * Constant);
+ this.Value = p == 0
+ ? 0
+ : p == 1
+ ? 1
+ : -Math.Pow(2, (10 * p) - 10) * Math.Sin(((p * 10) - 10.75) * Constant);
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InOutCirc.cs b/Dalamud/Interface/Animation/EasingFunctions/InOutCirc.cs
index a63ab648a..71a598dfb 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InOutCirc.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InOutCirc.cs
@@ -19,8 +19,8 @@ public class InOutCirc : Easing
public override void Update()
{
var p = this.Progress;
- this.ValueUnclamped = p < 0.5
- ? (1 - Math.Sqrt(1 - Math.Pow(2 * p, 2))) / 2
- : (Math.Sqrt(1 - Math.Pow((-2 * p) + 2, 2)) + 1) / 2;
+ this.Value = p < 0.5
+ ? (1 - Math.Sqrt(1 - Math.Pow(2 * p, 2))) / 2
+ : (Math.Sqrt(1 - Math.Pow((-2 * p) + 2, 2)) + 1) / 2;
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InOutCubic.cs b/Dalamud/Interface/Animation/EasingFunctions/InOutCubic.cs
index 4083265b7..07bcfa28d 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InOutCubic.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InOutCubic.cs
@@ -19,6 +19,6 @@ public class InOutCubic : Easing
public override void Update()
{
var p = this.Progress;
- this.ValueUnclamped = p < 0.5 ? 4 * p * p * p : 1 - (Math.Pow((-2 * p) + 2, 3) / 2);
+ this.Value = p < 0.5 ? 4 * p * p * p : 1 - (Math.Pow((-2 * p) + 2, 3) / 2);
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InOutElastic.cs b/Dalamud/Interface/Animation/EasingFunctions/InOutElastic.cs
index f27726038..f78f9f336 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InOutElastic.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InOutElastic.cs
@@ -21,12 +21,12 @@ public class InOutElastic : Easing
public override void Update()
{
var p = this.Progress;
- this.ValueUnclamped = p == 0
- ? 0
- : p == 1
- ? 1
- : p < 0.5
- ? -(Math.Pow(2, (20 * p) - 10) * Math.Sin(((20 * p) - 11.125) * Constant)) / 2
- : (Math.Pow(2, (-20 * p) + 10) * Math.Sin(((20 * p) - 11.125) * Constant) / 2) + 1;
+ this.Value = p == 0
+ ? 0
+ : p == 1
+ ? 1
+ : p < 0.5
+ ? -(Math.Pow(2, (20 * p) - 10) * Math.Sin(((20 * p) - 11.125) * Constant)) / 2
+ : (Math.Pow(2, (-20 * p) + 10) * Math.Sin(((20 * p) - 11.125) * Constant) / 2) + 1;
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InOutQuint.cs b/Dalamud/Interface/Animation/EasingFunctions/InOutQuint.cs
index e08129b25..64ab98b16 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InOutQuint.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InOutQuint.cs
@@ -19,6 +19,6 @@ public class InOutQuint : Easing
public override void Update()
{
var p = this.Progress;
- this.ValueUnclamped = p < 0.5 ? 16 * p * p * p * p * p : 1 - (Math.Pow((-2 * p) + 2, 5) / 2);
+ this.Value = p < 0.5 ? 16 * p * p * p * p * p : 1 - (Math.Pow((-2 * p) + 2, 5) / 2);
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InOutSine.cs b/Dalamud/Interface/Animation/EasingFunctions/InOutSine.cs
index cb940d87d..2f347ff80 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InOutSine.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InOutSine.cs
@@ -19,6 +19,6 @@ public class InOutSine : Easing
public override void Update()
{
var p = this.Progress;
- this.ValueUnclamped = -(Math.Cos(Math.PI * p) - 1) / 2;
+ this.Value = -(Math.Cos(Math.PI * p) - 1) / 2;
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InQuint.cs b/Dalamud/Interface/Animation/EasingFunctions/InQuint.cs
index 827e0e21b..a5ab5a22c 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InQuint.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InQuint.cs
@@ -19,6 +19,6 @@ public class InQuint : Easing
public override void Update()
{
var p = this.Progress;
- this.ValueUnclamped = p * p * p * p * p;
+ this.Value = p * p * p * p * p;
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/InSine.cs b/Dalamud/Interface/Animation/EasingFunctions/InSine.cs
index 61affa10a..fa079baad 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/InSine.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/InSine.cs
@@ -19,6 +19,6 @@ public class InSine : Easing
public override void Update()
{
var p = this.Progress;
- this.ValueUnclamped = 1 - Math.Cos((p * Math.PI) / 2);
+ this.Value = 1 - Math.Cos((p * Math.PI) / 2);
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/OutCirc.cs b/Dalamud/Interface/Animation/EasingFunctions/OutCirc.cs
index 980e29a81..b0d3b895a 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/OutCirc.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/OutCirc.cs
@@ -19,6 +19,6 @@ public class OutCirc : Easing
public override void Update()
{
var p = this.Progress;
- this.ValueUnclamped = Math.Sqrt(1 - Math.Pow(p - 1, 2));
+ this.Value = Math.Sqrt(1 - Math.Pow(p - 1, 2));
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/OutCubic.cs b/Dalamud/Interface/Animation/EasingFunctions/OutCubic.cs
index e1a79c35b..9c1bb57dc 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/OutCubic.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/OutCubic.cs
@@ -19,6 +19,6 @@ public class OutCubic : Easing
public override void Update()
{
var p = this.Progress;
- this.ValueUnclamped = 1 - Math.Pow(1 - p, 3);
+ this.Value = 1 - Math.Pow(1 - p, 3);
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/OutElastic.cs b/Dalamud/Interface/Animation/EasingFunctions/OutElastic.cs
index 1f525b404..6a4fcd6dc 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/OutElastic.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/OutElastic.cs
@@ -21,10 +21,10 @@ public class OutElastic : Easing
public override void Update()
{
var p = this.Progress;
- this.ValueUnclamped = p == 0
- ? 0
- : p == 1
- ? 1
- : (Math.Pow(2, -10 * p) * Math.Sin(((p * 10) - 0.75) * Constant)) + 1;
+ this.Value = p == 0
+ ? 0
+ : p == 1
+ ? 1
+ : (Math.Pow(2, -10 * p) * Math.Sin(((p * 10) - 0.75) * Constant)) + 1;
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/OutQuint.cs b/Dalamud/Interface/Animation/EasingFunctions/OutQuint.cs
index 24a2255d3..a3174e762 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/OutQuint.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/OutQuint.cs
@@ -19,6 +19,6 @@ public class OutQuint : Easing
public override void Update()
{
var p = this.Progress;
- this.ValueUnclamped = 1 - Math.Pow(1 - p, 5);
+ this.Value = 1 - Math.Pow(1 - p, 5);
}
}
diff --git a/Dalamud/Interface/Animation/EasingFunctions/OutSine.cs b/Dalamud/Interface/Animation/EasingFunctions/OutSine.cs
index a376d7f57..ba82232b3 100644
--- a/Dalamud/Interface/Animation/EasingFunctions/OutSine.cs
+++ b/Dalamud/Interface/Animation/EasingFunctions/OutSine.cs
@@ -19,6 +19,6 @@ public class OutSine : Easing
public override void Update()
{
var p = this.Progress;
- this.ValueUnclamped = Math.Sin((p * Math.PI) / 2);
+ this.Value = Math.Sin((p * Math.PI) / 2);
}
}
diff --git a/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs b/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs
index c63efca64..979f68bf8 100644
--- a/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs
@@ -252,7 +252,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
this.fadeOutEasing.Update();
- using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)this.fadeOutEasing.Value))
+ using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)Math.Max(this.fadeOutEasing.Value, 0)))
{
var i = 0;
foreach (var entry in entries)
@@ -393,7 +393,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
if (overrideAlpha)
{
- ImGui.PushStyleVar(ImGuiStyleVar.Alpha, showText ? (float)logoEasing.Value : 0f);
+ ImGui.PushStyleVar(ImGuiStyleVar.Alpha, showText ? (float)Math.Min(logoEasing.Value, 1) : 0f);
}
// Drop shadow
From 335b3d1ed5edf1325bbbed67984f6d0be2e92222 Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 30 Dec 2024 14:01:12 +0100
Subject: [PATCH 49/88] add todo to re-apply easings behavior change
---
Dalamud/Interface/Animation/Easing.cs | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Dalamud/Interface/Animation/Easing.cs b/Dalamud/Interface/Animation/Easing.cs
index edab25149..473e3d5e1 100644
--- a/Dalamud/Interface/Animation/Easing.cs
+++ b/Dalamud/Interface/Animation/Easing.cs
@@ -1,11 +1,14 @@
using System.Diagnostics;
using System.Numerics;
+using Dalamud.Utility;
+
namespace Dalamud.Interface.Animation;
///
/// Base class facilitating the implementation of easing functions.
///
+[Api11ToDo("Re-apply https://github.com/goatcorp/Dalamud/commit/1aada983931d9e45a250eebbc17c8b782d07701b")]
public abstract class Easing
{
// TODO: Use game delta time here instead
From 49a18e3c1ed328f74c559657635b66e1008ad26c Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 30 Dec 2024 14:01:50 +0100
Subject: [PATCH 50/88] Api11ToDo -> Api12ToDo
---
Dalamud/Game/ClientState/Objects/ObjectTable.cs | 2 +-
Dalamud/Game/Gui/Dtr/DtrBarEntry.cs | 2 +-
Dalamud/Interface/Animation/Easing.cs | 2 +-
.../{Api11ToDoAttribute.cs => Api12ToDoAttribute.cs} | 6 +++---
Dalamud/Utility/SeStringExtensions.cs | 4 ++--
5 files changed, 8 insertions(+), 8 deletions(-)
rename Dalamud/Utility/{Api11ToDoAttribute.cs => Api12ToDoAttribute.cs} (75%)
diff --git a/Dalamud/Game/ClientState/Objects/ObjectTable.cs b/Dalamud/Game/ClientState/Objects/ObjectTable.cs
index 8ea1b582f..6aa7fd8ad 100644
--- a/Dalamud/Game/ClientState/Objects/ObjectTable.cs
+++ b/Dalamud/Game/ClientState/Objects/ObjectTable.cs
@@ -155,7 +155,7 @@ internal sealed partial class ObjectTable : IServiceType, IObjectTable
};
}
- [Api11ToDo("Use ThreadSafety.AssertMainThread() instead of this.")]
+ [Api12ToDo("Use ThreadSafety.AssertMainThread() instead of this.")]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool WarnMultithreadedUsage()
{
diff --git a/Dalamud/Game/Gui/Dtr/DtrBarEntry.cs b/Dalamud/Game/Gui/Dtr/DtrBarEntry.cs
index 8ba46f999..49a2cbb73 100644
--- a/Dalamud/Game/Gui/Dtr/DtrBarEntry.cs
+++ b/Dalamud/Game/Gui/Dtr/DtrBarEntry.cs
@@ -145,7 +145,7 @@ internal sealed unsafe class DtrBarEntry : IDisposable, IDtrBarEntry
}
///
- [Api11ToDo("Maybe make this config scoped to internalname?")]
+ [Api12ToDo("Maybe make this config scoped to internalname?")]
public bool UserHidden => this.configuration.DtrIgnore?.Contains(this.Title) ?? false;
///
diff --git a/Dalamud/Interface/Animation/Easing.cs b/Dalamud/Interface/Animation/Easing.cs
index 473e3d5e1..c6d6149af 100644
--- a/Dalamud/Interface/Animation/Easing.cs
+++ b/Dalamud/Interface/Animation/Easing.cs
@@ -8,7 +8,7 @@ namespace Dalamud.Interface.Animation;
///
/// Base class facilitating the implementation of easing functions.
///
-[Api11ToDo("Re-apply https://github.com/goatcorp/Dalamud/commit/1aada983931d9e45a250eebbc17c8b782d07701b")]
+[Api12ToDo("Re-apply https://github.com/goatcorp/Dalamud/commit/1aada983931d9e45a250eebbc17c8b782d07701b")]
public abstract class Easing
{
// TODO: Use game delta time here instead
diff --git a/Dalamud/Utility/Api11ToDoAttribute.cs b/Dalamud/Utility/Api12ToDoAttribute.cs
similarity index 75%
rename from Dalamud/Utility/Api11ToDoAttribute.cs
rename to Dalamud/Utility/Api12ToDoAttribute.cs
index 0336120ba..9f871274d 100644
--- a/Dalamud/Utility/Api11ToDoAttribute.cs
+++ b/Dalamud/Utility/Api12ToDoAttribute.cs
@@ -4,7 +4,7 @@ namespace Dalamud.Utility;
/// Utility class for marking something to be changed for API 11, for ease of lookup.
///
[AttributeUsage(AttributeTargets.All, Inherited = false)]
-internal sealed class Api11ToDoAttribute : Attribute
+internal sealed class Api12ToDoAttribute : Attribute
{
///
/// Marks that this should be made internal.
@@ -12,11 +12,11 @@ internal sealed class Api11ToDoAttribute : Attribute
public const string MakeInternal = "Make internal.";
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// The explanation.
/// The explanation 2.
- public Api11ToDoAttribute(string what, string what2 = "")
+ public Api12ToDoAttribute(string what, string what2 = "")
{
_ = what;
_ = what2;
diff --git a/Dalamud/Utility/SeStringExtensions.cs b/Dalamud/Utility/SeStringExtensions.cs
index 34ebb1450..057759e1e 100644
--- a/Dalamud/Utility/SeStringExtensions.cs
+++ b/Dalamud/Utility/SeStringExtensions.cs
@@ -43,7 +43,7 @@ public static class SeStringExtensions
/// Macro string in UTF-8 to compile and append to .
/// this for method chaining.
[Obsolete($"Use {nameof(LSeStringBuilder)}.{nameof(LSeStringBuilder.AppendMacroString)} directly instead.", true)]
- [Api11ToDo("Remove")]
+ [Api12ToDo("Remove")]
public static LSeStringBuilder AppendMacroString(this LSeStringBuilder ssb, ReadOnlySpan macroString) =>
ssb.AppendMacroString(macroString, new() { ExceptionMode = MacroStringParseExceptionMode.EmbedError });
@@ -52,7 +52,7 @@ public static class SeStringExtensions
/// Macro string in UTF-16 to compile and append to .
/// this for method chaining.
[Obsolete($"Use {nameof(LSeStringBuilder)}.{nameof(LSeStringBuilder.AppendMacroString)} directly instead.", true)]
- [Api11ToDo("Remove")]
+ [Api12ToDo("Remove")]
public static LSeStringBuilder AppendMacroString(this LSeStringBuilder ssb, ReadOnlySpan macroString) =>
ssb.AppendMacroString(macroString, new() { ExceptionMode = MacroStringParseExceptionMode.EmbedError });
From 35b49823e5e5883f25220f4ab651487fc4344ff4 Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 30 Dec 2024 21:14:08 +0100
Subject: [PATCH 51/88] WindowSystem: fix clickthrough option not applying to
child windows, persist options Persistence is pretty WIP. I want to offer
multiple presets in the future, and save more things like window positions.
---
.../Internal/DalamudConfiguration.cs | 9 +-
.../Interface/Internal/InterfaceManager.cs | 3 +
.../Settings/Tabs/SettingsTabExperimental.cs | 16 +-
.../Windows/Settings/Tabs/SettingsTabLook.cs | 20 +-
.../Windowing/Persistence/PresetModel.cs | 53 +++++
.../Persistence/WindowSystemPersistence.cs | 47 ++++
Dalamud/Interface/Windowing/Window.cs | 213 +++++++++++++-----
Dalamud/Interface/Windowing/WindowSystem.cs | 18 +-
lib/cimgui | 2 +-
9 files changed, 301 insertions(+), 80 deletions(-)
create mode 100644 Dalamud/Interface/Windowing/Persistence/PresetModel.cs
create mode 100644 Dalamud/Interface/Windowing/Persistence/WindowSystemPersistence.cs
diff --git a/Dalamud/Configuration/Internal/DalamudConfiguration.cs b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
index 850aeb7e9..515556b7e 100644
--- a/Dalamud/Configuration/Internal/DalamudConfiguration.cs
+++ b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
@@ -12,6 +12,7 @@ using Dalamud.Interface.FontIdentifier;
using Dalamud.Interface.Internal;
using Dalamud.Interface.Internal.ReShadeHandling;
using Dalamud.Interface.Style;
+using Dalamud.Interface.Windowing.Persistence;
using Dalamud.IoC.Internal;
using Dalamud.Plugin.Internal.AutoUpdate;
using Dalamud.Plugin.Internal.Profiles;
@@ -264,8 +265,7 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
/// Gets or sets a value indicating whether or not an additional button allowing pinning and clickthrough options should be shown
/// on plugin title bars when using the Window System.
///
- [JsonProperty("EnablePluginUiAdditionalOptionsExperimental")]
- public bool EnablePluginUiAdditionalOptions { get; set; } = false;
+ public bool EnablePluginUiAdditionalOptions { get; set; } = true;
///
/// Gets or sets a value indicating whether viewports should always be disabled.
@@ -351,6 +351,11 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
///
public bool ProfilesHasSeenTutorial { get; set; } = false;
+ ///
+ /// Gets or sets the default UI preset.
+ ///
+ public PresetModel DefaultUiPreset { get; set; } = new();
+
///
/// Gets or sets the order of DTR elements, by title.
///
diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs
index 2908be34a..1cd45f4f4 100644
--- a/Dalamud/Interface/Internal/InterfaceManager.cs
+++ b/Dalamud/Interface/Internal/InterfaceManager.cs
@@ -27,6 +27,8 @@ using Dalamud.Interface.ManagedFontAtlas.Internals;
using Dalamud.Interface.Style;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Windowing;
+using Dalamud.Interface.Windowing.Persistence;
+using Dalamud.IoC.Internal;
using Dalamud.Logging.Internal;
using Dalamud.Utility;
using Dalamud.Utility.Timing;
@@ -60,6 +62,7 @@ namespace Dalamud.Interface.Internal;
/// This class manages interaction with the ImGui interface.
///
[ServiceManager.EarlyLoadedService]
+[InherentDependency] // Used by window system windows to restore state from the configuration
internal partial class InterfaceManager : IInternalDisposableService
{
///
diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs
index 4354daffe..1aae0dfb3 100644
--- a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs
+++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs
@@ -39,18 +39,6 @@ public class SettingsTabExperimental : SettingsTab
new GapSettingsEntry(5),
- new SettingsEntry(
- Loc.Localize(
- "DalamudSettingEnablePluginUIAdditionalOptions",
- "Add a button to the title bar of plugin windows to open additional options"),
- Loc.Localize(
- "DalamudSettingEnablePluginUIAdditionalOptionsHint",
- "This will allow you to pin certain plugin windows, make them clickthrough or adjust their opacity.\nThis may not be supported by all of your plugins. Contact the plugin author if you want them to support this feature."),
- c => c.EnablePluginUiAdditionalOptions,
- (v, c) => c.EnablePluginUiAdditionalOptions = v),
-
- new GapSettingsEntry(5),
-
new ButtonSettingsEntry(
Loc.Localize("DalamudSettingsClearHidden", "Clear hidden plugins"),
Loc.Localize(
@@ -65,7 +53,7 @@ public class SettingsTabExperimental : SettingsTab
new GapSettingsEntry(5, true),
new DevPluginsSettingsEntry(),
-
+
new SettingsEntry(
Loc.Localize(
"DalamudSettingEnableImGuiAsserts",
@@ -75,7 +63,7 @@ public class SettingsTabExperimental : SettingsTab
"If this setting is enabled, a window containing further details will be shown when an internal assertion in ImGui fails.\nWe recommend enabling this when developing plugins."),
c => Service.Get().ShowAsserts,
(v, _) => Service.Get().ShowAsserts = v),
-
+
new SettingsEntry(
Loc.Localize(
"DalamudSettingEnableImGuiAssertsAtStartup",
diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs
index 61ab00936..7f75dbf29 100644
--- a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs
+++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs
@@ -24,7 +24,7 @@ namespace Dalamud.Interface.Internal.Windows.Settings.Tabs;
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")]
public class SettingsTabLook : SettingsTab
{
- private static readonly (string, float)[] GlobalUiScalePresets =
+ private static readonly (string, float)[] GlobalUiScalePresets =
{
("80%##DalamudSettingsGlobalUiScaleReset96", 0.8f),
("100%##DalamudSettingsGlobalUiScaleReset12", 1f),
@@ -107,7 +107,17 @@ public class SettingsTabLook : SettingsTab
Loc.Localize("DalamudSettingToggleDockingHint", "This will allow you to fuse and tab plugin windows."),
c => c.IsDocking,
(v, c) => c.IsDocking = v),
-
+
+ new SettingsEntry(
+ Loc.Localize(
+ "DalamudSettingEnablePluginUIAdditionalOptions",
+ "Add a button to the title bar of plugin windows to open additional options"),
+ Loc.Localize(
+ "DalamudSettingEnablePluginUIAdditionalOptionsHint",
+ "This will allow you to pin certain plugin windows, make them clickthrough or adjust their opacity.\nThis may not be supported by all of your plugins. Contact the plugin author if you want them to support this feature."),
+ c => c.EnablePluginUiAdditionalOptions,
+ (v, c) => c.EnablePluginUiAdditionalOptions = v),
+
new SettingsEntry(
Loc.Localize("DalamudSettingEnablePluginUISoundEffects", "Enable sound effects for plugin windows"),
Loc.Localize("DalamudSettingEnablePluginUISoundEffectsHint", "This will allow you to enable or disable sound effects generated by plugin user interfaces.\nThis is affected by your in-game `System Sounds` volume settings."),
@@ -125,19 +135,19 @@ public class SettingsTabLook : SettingsTab
Loc.Localize("DalamudSettingToggleTsmHint", "This will allow you to access certain Dalamud and Plugin functionality from the title screen.\nDisabling this will also hide the Dalamud version text on the title screen."),
c => c.ShowTsm,
(v, c) => c.ShowTsm = v),
-
+
new SettingsEntry(
Loc.Localize("DalamudSettingInstallerOpenDefault", "Open the Plugin Installer to the \"Installed Plugins\" tab by default"),
Loc.Localize("DalamudSettingInstallerOpenDefaultHint", "This will allow you to open the Plugin Installer to the \"Installed Plugins\" tab by default, instead of the \"Available Plugins\" tab."),
c => c.PluginInstallerOpen == PluginInstallerOpenKind.InstalledPlugins,
(v, c) => c.PluginInstallerOpen = v ? PluginInstallerOpenKind.InstalledPlugins : PluginInstallerOpenKind.AllPlugins),
-
+
new SettingsEntry(
Loc.Localize("DalamudSettingReducedMotion", "Reduce motions"),
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."),
diff --git a/Dalamud/Interface/Windowing/Persistence/PresetModel.cs b/Dalamud/Interface/Windowing/Persistence/PresetModel.cs
new file mode 100644
index 000000000..db91bad8a
--- /dev/null
+++ b/Dalamud/Interface/Windowing/Persistence/PresetModel.cs
@@ -0,0 +1,53 @@
+using System.Collections.Generic;
+
+using Newtonsoft.Json;
+
+namespace Dalamud.Interface.Windowing.Persistence;
+
+///
+/// Class representing a Window System preset.
+///
+internal class PresetModel
+{
+ ///
+ /// Gets or sets the ID of this preset.
+ ///
+ [JsonProperty("id")]
+ public Guid Id { get; set; }
+
+ ///
+ /// Gets or sets the name of this preset.
+ ///
+ [JsonProperty("n")]
+ public string Name { get; set; } = "New Preset";
+
+ ///
+ /// Gets or sets a dictionary containing the windows in the preset, mapping their ID to the preset.
+ ///
+ [JsonProperty("w")]
+ public Dictionary Windows { get; set; } = new();
+
+ ///
+ /// Class representing a window in a preset.
+ ///
+ internal class PresetWindow
+ {
+ ///
+ /// Gets or sets a value indicating whether the window is pinned.
+ ///
+ [JsonProperty("p")]
+ public bool IsPinned { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the window is clickthrough.
+ ///
+ [JsonProperty("ct")]
+ public bool IsClickThrough { get; set; }
+
+ ///
+ /// Gets or sets the window's opacity override.
+ ///
+ [JsonProperty("a")]
+ public float? Alpha { get; set; }
+ }
+}
diff --git a/Dalamud/Interface/Windowing/Persistence/WindowSystemPersistence.cs b/Dalamud/Interface/Windowing/Persistence/WindowSystemPersistence.cs
new file mode 100644
index 000000000..8b884b0e5
--- /dev/null
+++ b/Dalamud/Interface/Windowing/Persistence/WindowSystemPersistence.cs
@@ -0,0 +1,47 @@
+using Dalamud.Configuration.Internal;
+
+namespace Dalamud.Interface.Windowing.Persistence;
+
+///
+/// Class handling persistence for window system windows.
+///
+[ServiceManager.EarlyLoadedService]
+internal class WindowSystemPersistence : IServiceType
+{
+ [ServiceManager.ServiceDependency]
+ private readonly DalamudConfiguration config = Service.Get();
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ [ServiceManager.ServiceConstructor]
+ public WindowSystemPersistence()
+ {
+ }
+
+ ///
+ /// Gets the active window system preset.
+ ///
+ public PresetModel ActivePreset => this.config.DefaultUiPreset;
+
+ ///
+ /// Get or add a window to the active preset.
+ ///
+ /// The ID of the window.
+ /// The preset window instance, or null if the preset does not contain this window.
+ public PresetModel.PresetWindow? GetWindow(uint id)
+ {
+ return this.ActivePreset.Windows.TryGetValue(id, out var window) ? window : null;
+ }
+
+ ///
+ /// Persist the state of a window to the active preset.
+ ///
+ /// The ID of the window.
+ /// The preset window instance.
+ public void SaveWindow(uint id, PresetModel.PresetWindow window)
+ {
+ this.ActivePreset.Windows[id] = window;
+ this.config.QueueSave();
+ }
+}
diff --git a/Dalamud/Interface/Windowing/Window.cs b/Dalamud/Interface/Windowing/Window.cs
index 589217a73..6219de852 100644
--- a/Dalamud/Interface/Windowing/Window.cs
+++ b/Dalamud/Interface/Windowing/Window.cs
@@ -1,15 +1,17 @@
using System.Collections.Generic;
+using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using CheapLoc;
-using Dalamud.Configuration.Internal;
using Dalamud.Game.ClientState.Keys;
using Dalamud.Interface.Colors;
+using Dalamud.Interface.Components;
using Dalamud.Interface.Internal;
using Dalamud.Interface.Utility;
+using Dalamud.Interface.Windowing.Persistence;
using Dalamud.Logging.Internal;
using FFXIVClientStructs.FFXIV.Client.UI;
@@ -26,7 +28,7 @@ public abstract class Window
private static readonly ModuleLog Log = new("WindowSystem");
private static bool wasEscPressedLastFrame = false;
-
+
private bool internalLastIsOpen = false;
private bool internalIsOpen = false;
private bool internalIsPinned = false;
@@ -35,15 +37,19 @@ public abstract class Window
private float? internalAlpha = null;
private bool nextFrameBringToFront = false;
+ private bool hasInitializedFromPreset = false;
+ private PresetModel.PresetWindow? presetWindow;
+ private bool presetDirty = false;
+
///
/// Initializes a new instance of the class.
///
/// The name/ID of this window.
/// If you have multiple windows with the same name, you will need to
- /// append an unique ID to it by specifying it after "###" behind the window title.
+ /// append a unique ID to it by specifying it after "###" behind the window title.
///
/// The of this window.
- /// Whether or not this window should be limited to the main game window.
+ /// Whether this window should be limited to the main game window.
protected Window(string name, ImGuiWindowFlags flags = ImGuiWindowFlags.None, bool forceMainWindow = false)
{
this.WindowName = name;
@@ -51,6 +57,33 @@ public abstract class Window
this.ForceMainWindow = forceMainWindow;
}
+ ///
+ /// Flags to control window behavior.
+ ///
+ [Flags]
+ internal enum WindowDrawFlags
+ {
+ ///
+ /// Nothing.
+ ///
+ None = 0,
+
+ ///
+ /// Enable window opening/closing sound effects.
+ ///
+ UseSoundEffects = 1 << 0,
+
+ ///
+ /// Hook into the game's focus management.
+ ///
+ UseFocusManagement = 1 << 1,
+
+ ///
+ /// Enable the built-in "additional options" menu on the title bar.
+ ///
+ UseAdditionalOptions = 1 << 2,
+ }
+
///
/// Gets or sets the namespace of the window.
///
@@ -87,7 +120,7 @@ public abstract class Window
/// Gets or sets a value representing the sound effect id to be played when the window is closed.
///
public uint OnCloseSfxId { get; set; } = 24u;
-
+
///
/// Gets or sets the position of this window.
///
@@ -155,7 +188,7 @@ public abstract class Window
///
/// Gets or sets a list of available title bar buttons.
- ///
+ ///
/// If or are set to true, and this features is not
/// disabled globally by the user, an internal title bar button to manage these is added when drawing, but it will
/// not appear in this collection. If you wish to remove this button, set both of these values to false.
@@ -170,7 +203,7 @@ public abstract class Window
get => this.internalIsOpen;
set => this.internalIsOpen = value;
}
-
+
private bool CanShowCloseButton => this.ShowCloseButton && !this.internalIsClickthrough;
///
@@ -267,17 +300,16 @@ public abstract class Window
public virtual void Update()
{
}
-
+
///
/// Draw the window via ImGui.
///
- /// Configuration instance used to check if certain window management features should be enabled.
- internal void DrawInternal(DalamudConfiguration? configuration)
+ /// Flags controlling window behavior.
+ /// Handler for window persistence data.
+ internal void DrawInternal(WindowDrawFlags internalDrawFlags, WindowSystemPersistence? persistence)
{
this.PreOpenCheck();
- var doSoundEffects = configuration?.EnablePluginUISoundEffects ?? false;
-
if (!this.IsOpen)
{
if (this.internalIsOpen != this.internalLastIsOpen)
@@ -286,8 +318,9 @@ public abstract class Window
this.OnClose();
this.IsFocused = false;
-
- if (doSoundEffects && !this.DisableWindowSounds) UIGlobals.PlaySoundEffect(this.OnCloseSfxId);
+
+ if (internalDrawFlags.HasFlag(WindowDrawFlags.UseSoundEffects) && !this.DisableWindowSounds)
+ UIGlobals.PlaySoundEffect(this.OnCloseSfxId);
}
return;
@@ -301,13 +334,16 @@ public abstract class Window
if (hasNamespace)
ImGui.PushID(this.Namespace);
-
+
+ this.PreHandlePreset(persistence);
+
if (this.internalLastIsOpen != this.internalIsOpen && this.internalIsOpen)
{
this.internalLastIsOpen = this.internalIsOpen;
this.OnOpen();
- if (doSoundEffects && !this.DisableWindowSounds) UIGlobals.PlaySoundEffect(this.OnOpenSfxId);
+ if (internalDrawFlags.HasFlag(WindowDrawFlags.UseSoundEffects) && !this.DisableWindowSounds)
+ UIGlobals.PlaySoundEffect(this.OnOpenSfxId);
}
this.PreDraw();
@@ -340,6 +376,8 @@ public abstract class Window
if (this.CanShowCloseButton ? ImGui.Begin(this.WindowName, ref this.internalIsOpen, flags) : ImGui.Begin(this.WindowName, flags))
{
+ ImGuiNativeAdditions.igCustom_WindowSetInheritNoInputs(this.internalIsClickthrough);
+
// Draw the actual window contents
try
{
@@ -355,7 +393,7 @@ public abstract class Window
var flagsApplicableForTitleBarIcons = !flags.HasFlag(ImGuiWindowFlags.NoDecoration) &&
!flags.HasFlag(ImGuiWindowFlags.NoTitleBar);
var showAdditions = (this.AllowPinning || this.AllowClickthrough) &&
- (configuration?.EnablePluginUiAdditionalOptions ?? true) &&
+ internalDrawFlags.HasFlag(WindowDrawFlags.UseAdditionalOptions) &&
flagsApplicableForTitleBarIcons;
if (showAdditions)
{
@@ -364,10 +402,10 @@ public abstract class Window
if (ImGui.BeginPopup(additionsPopupName, ImGuiWindowFlags.NoMove))
{
var isAvailable = ImGuiHelpers.CheckIsWindowOnMainViewport();
-
+
if (!isAvailable)
ImGui.BeginDisabled();
-
+
if (this.internalIsClickthrough)
ImGui.BeginDisabled();
@@ -375,36 +413,51 @@ public abstract class Window
{
var showAsPinned = this.internalIsPinned || this.internalIsClickthrough;
if (ImGui.Checkbox(Loc.Localize("WindowSystemContextActionPin", "Pin Window"), ref showAsPinned))
+ {
this.internalIsPinned = showAsPinned;
+ this.presetDirty = true;
+ }
+
+ ImGuiComponents.HelpMarker(
+ Loc.Localize("WindowSystemContextActionPinHint", "Pinned windows will not move or resize when you click and drag them."));
}
if (this.internalIsClickthrough)
ImGui.EndDisabled();
if (this.AllowClickthrough)
- ImGui.Checkbox(Loc.Localize("WindowSystemContextActionClickthrough", "Make clickthrough"), ref this.internalIsClickthrough);
+ {
+ if (ImGui.Checkbox(
+ Loc.Localize("WindowSystemContextActionClickthrough", "Make clickthrough"),
+ ref this.internalIsClickthrough))
+ {
+ this.presetDirty = true;
+ }
+
+ ImGuiComponents.HelpMarker(
+ Loc.Localize("WindowSystemContextActionClickthroughHint", "Clickthrough windows will not receive mouse input, move or resize. They are completely inert."));
+ }
var alpha = (this.internalAlpha ?? ImGui.GetStyle().Alpha) * 100f;
if (ImGui.SliderFloat(Loc.Localize("WindowSystemContextActionAlpha", "Opacity"), ref alpha, 20f,
100f))
{
this.internalAlpha = alpha / 100f;
+ this.presetDirty = true;
}
ImGui.SameLine();
if (ImGui.Button(Loc.Localize("WindowSystemContextActionReset", "Reset")))
{
this.internalAlpha = null;
+ this.presetDirty = true;
}
if (isAvailable)
{
ImGui.TextColored(ImGuiColors.DalamudGrey,
Loc.Localize("WindowSystemContextActionClickthroughDisclaimer",
- "Open this menu again to disable clickthrough."));
- ImGui.TextColored(ImGuiColors.DalamudGrey,
- Loc.Localize("WindowSystemContextActionDisclaimer",
- "These options may not work for all plugins at the moment."));
+ "Open this menu again by clicking the three dashes to disable clickthrough."));
}
else
{
@@ -415,7 +468,7 @@ public abstract class Window
if (!isAvailable)
ImGui.EndDisabled();
-
+
ImGui.EndPopup();
}
@@ -457,8 +510,7 @@ public abstract class Window
this.IsFocused = ImGui.IsWindowFocused(ImGuiFocusedFlags.RootAndChildWindows);
- var isAllowed = configuration?.IsFocusManagementEnabled ?? false;
- if (isAllowed)
+ if (internalDrawFlags.HasFlag(WindowDrawFlags.UseFocusManagement))
{
var escapeDown = Service.Get()[VirtualKey.ESCAPE];
if (escapeDown && this.IsFocused && !wasEscPressedLastFrame && this.RespectCloseHotkey)
@@ -476,6 +528,8 @@ public abstract class Window
this.PostDraw();
+ this.PostHandlePreset(persistence);
+
if (hasNamespace)
ImGui.PopID();
}
@@ -511,7 +565,7 @@ public abstract class Window
{
ImGui.SetNextWindowBgAlpha(this.BgAlpha.Value);
}
-
+
// Manually set alpha takes precedence, if devs don't want that, they should turn it off
if (this.internalAlpha.HasValue)
{
@@ -519,21 +573,65 @@ public abstract class Window
}
}
+ private void PreHandlePreset(WindowSystemPersistence? persistence)
+ {
+ if (persistence == null || this.hasInitializedFromPreset)
+ return;
+
+ var id = ImGui.GetID(this.WindowName);
+ this.presetWindow = persistence.GetWindow(id);
+
+ this.hasInitializedFromPreset = true;
+
+ // Fresh preset - don't apply anything
+ if (this.presetWindow == null)
+ {
+ this.presetWindow = new PresetModel.PresetWindow();
+ this.presetDirty = true;
+ return;
+ }
+
+ this.internalIsPinned = this.presetWindow.IsPinned;
+ this.internalIsClickthrough = this.presetWindow.IsClickThrough;
+ this.internalAlpha = this.presetWindow.Alpha;
+ }
+
+ private void PostHandlePreset(WindowSystemPersistence? persistence)
+ {
+ if (persistence == null)
+ return;
+
+ Debug.Assert(this.presetWindow != null, "this.presetWindow != null");
+
+ if (this.presetDirty)
+ {
+ this.presetWindow.IsPinned = this.internalIsPinned;
+ this.presetWindow.IsClickThrough = this.internalIsClickthrough;
+ this.presetWindow.Alpha = this.internalAlpha;
+
+ var id = ImGui.GetID(this.WindowName);
+ persistence.SaveWindow(id, this.presetWindow!);
+ this.presetDirty = false;
+
+ Log.Verbose("Saved preset for {WindowName}", this.WindowName);
+ }
+ }
+
private unsafe void DrawTitleBarButtons(void* window, ImGuiWindowFlags flags, Vector4 titleBarRect, IEnumerable buttons)
{
ImGui.PushClipRect(ImGui.GetWindowPos(), ImGui.GetWindowPos() + ImGui.GetWindowSize(), false);
-
+
var style = ImGui.GetStyle();
var fontSize = ImGui.GetFontSize();
var drawList = ImGui.GetWindowDrawList();
-
+
var padR = 0f;
var buttonSize = ImGui.GetFontSize();
var numNativeButtons = 0;
if (this.CanShowCloseButton)
numNativeButtons++;
-
+
if (!flags.HasFlag(ImGuiWindowFlags.NoCollapse) && style.WindowMenuButtonPosition == ImGuiDir.Right)
numNativeButtons++;
@@ -543,15 +641,15 @@ public abstract class Window
// Pad to the left, to get out of the way of the native buttons
padR += numNativeButtons * (buttonSize + style.ItemInnerSpacing.X);
-
- Vector2 GetCenter(Vector4 rect) => new((rect.X + rect.Z) * 0.5f, (rect.Y + rect.W) * 0.5f);
+
+ Vector2 GetCenter(Vector4 rect) => new((rect.X + rect.Z) * 0.5f, (rect.Y + rect.W) * 0.5f);
var numButtons = 0;
bool DrawButton(TitleBarButton button, Vector2 pos)
{
var id = ImGui.GetID($"###CustomTbButton{numButtons}");
numButtons++;
-
+
var min = pos;
var max = pos + new Vector2(fontSize, fontSize);
Vector4 bb = new(min.X, min.Y, max.X, max.Y);
@@ -563,12 +661,12 @@ public abstract class Window
{
hovered = false;
held = false;
-
+
// ButtonBehavior does not function if the window is clickthrough, so we have to do it ourselves
if (ImGui.IsMouseHoveringRect(min, max))
{
hovered = true;
-
+
// We can't use ImGui native functions here, because they don't work with clickthrough
if ((User32.GetKeyState((int)VirtualKey.LBUTTON) & 0x8000) != 0)
{
@@ -581,7 +679,7 @@ public abstract class Window
{
pressed = ImGuiNativeAdditions.igButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags.None);
}
-
+
if (isClipped)
return pressed;
@@ -590,10 +688,10 @@ public abstract class Window
var textCol = ImGui.GetColorU32(ImGuiCol.Text);
if (hovered || held)
drawList.AddCircleFilled(GetCenter(bb) + new Vector2(0.0f, -0.5f), (fontSize * 0.5f) + 1.0f, bgCol);
-
+
var offset = button.IconOffset * ImGuiHelpers.GlobalScale;
drawList.AddText(InterfaceManager.IconFont, (float)(fontSize * 0.8), new Vector2(bb.X + offset.X, bb.Y + offset.Y), textCol, button.Icon.ToIconString());
-
+
if (hovered)
button.ShowTooltip?.Invoke();
@@ -608,14 +706,14 @@ public abstract class Window
{
if (this.internalIsClickthrough && !button.AvailableClickthrough)
return;
-
+
Vector2 position = new(titleBarRect.Z - padR - buttonSize, titleBarRect.Y + style.FramePadding.Y);
padR += buttonSize + style.ItemInnerSpacing.X;
-
+
if (DrawButton(button, position))
button.Click?.Invoke(ImGuiMouseButton.Left);
}
-
+
ImGui.PopClipRect();
}
@@ -625,7 +723,7 @@ public abstract class Window
public struct WindowSizeConstraints
{
private Vector2 internalMaxSize = new(float.MaxValue);
-
+
///
/// Initializes a new instance of the struct.
///
@@ -637,7 +735,7 @@ public abstract class Window
/// Gets or sets the minimum size of the window.
///
public Vector2 MinimumSize { get; set; } = new(0);
-
+
///
/// Gets or sets the maximum size of the window.
///
@@ -646,12 +744,12 @@ public abstract class Window
get => this.GetSafeMaxSize();
set => this.internalMaxSize = value;
}
-
+
private Vector2 GetSafeMaxSize()
{
var currentMin = this.MinimumSize;
- if (this.internalMaxSize.X < currentMin.X || this.internalMaxSize.Y < currentMin.Y)
+ if (this.internalMaxSize.X < currentMin.X || this.internalMaxSize.Y < currentMin.Y)
return new Vector2(float.MaxValue);
return this.internalMaxSize;
@@ -667,53 +765,56 @@ public abstract class Window
/// Gets or sets the icon of the button.
///
public FontAwesomeIcon Icon { get; set; }
-
+
///
/// Gets or sets a vector by which the position of the icon within the button shall be offset.
/// Automatically scaled by the global font scale for you.
///
public Vector2 IconOffset { get; set; }
-
+
///
/// Gets or sets an action that is called when a tooltip shall be drawn.
/// May be null if no tooltip shall be drawn.
///
public Action? ShowTooltip { get; set; }
-
+
///
/// Gets or sets an action that is called when the button is clicked.
///
public Action Click { get; set; }
-
+
///
/// Gets or sets the priority the button shall be shown in.
/// Lower = closer to ImGui default buttons.
///
public int Priority { get; set; }
-
+
///
/// Gets or sets a value indicating whether or not the button shall be clickable
/// when the respective window is set to clickthrough.
///
public bool AvailableClickthrough { get; set; }
}
-
+
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "imports")]
private static unsafe class ImGuiNativeAdditions
{
[DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)]
public static extern bool igItemAdd(Vector4 bb, uint id, Vector4* navBb, uint flags);
-
+
[DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)]
public static extern bool igButtonBehavior(Vector4 bb, uint id, bool* outHovered, bool* outHeld, ImGuiButtonFlags flags);
-
+
[DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)]
public static extern void* igGetCurrentWindow();
-
+
[DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)]
public static extern void igStartMouseMovingWindow(void* window);
-
+
[DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)]
public static extern void ImGuiWindow_TitleBarRect(Vector4* pOut, void* window);
+
+ [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void igCustom_WindowSetInheritNoInputs(bool inherit);
}
}
diff --git a/Dalamud/Interface/Windowing/WindowSystem.cs b/Dalamud/Interface/Windowing/WindowSystem.cs
index a3eab2a60..f79eea025 100644
--- a/Dalamud/Interface/Windowing/WindowSystem.cs
+++ b/Dalamud/Interface/Windowing/WindowSystem.cs
@@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Linq;
using Dalamud.Configuration.Internal;
+using Dalamud.Interface.Windowing.Persistence;
using ImGuiNET;
using Serilog;
@@ -103,15 +104,28 @@ public class WindowSystem
if (hasNamespace)
ImGui.PushID(this.Namespace);
+ // These must be nullable, people are using stock WindowSystems and Windows without Dalamud for tests
var config = Service.GetNullable();
+ var persistence = Service.GetNullable();
+
+ var flags = Window.WindowDrawFlags.None;
+
+ if (config?.EnablePluginUISoundEffects ?? false)
+ flags |= Window.WindowDrawFlags.UseSoundEffects;
+
+ if (config?.EnablePluginUiAdditionalOptions ?? false)
+ flags |= Window.WindowDrawFlags.UseAdditionalOptions;
+
+ if (config?.IsFocusManagementEnabled ?? false)
+ flags |= Window.WindowDrawFlags.UseFocusManagement;
// Shallow clone the list of windows so that we can edit it without modifying it while the loop is iterating
foreach (var window in this.windows.ToArray())
{
#if DEBUG
- // Log.Verbose($"[WS{(hasNamespace ? "/" + this.Namespace : string.Empty)}] Drawing {window.WindowName}");
+ // Log.Verbose($"[WS{(hasNamespace ? "/" + this.Namespace : string.Empty)}] Drawing {window.WindowName}");
#endif
- window.DrawInternal(config);
+ window.DrawInternal(flags, persistence);
}
var focusedWindow = this.windows.FirstOrDefault(window => window.IsFocused && window.RespectCloseHotkey);
diff --git a/lib/cimgui b/lib/cimgui
index 7002b2884..122ee1681 160000
--- a/lib/cimgui
+++ b/lib/cimgui
@@ -1 +1 @@
-Subproject commit 7002b2884e9216d8bef3e792722d88abe31788f8
+Subproject commit 122ee16819437eea7eefe0c04398b44174106d86
From cac76f045b6acd6124415172e27f9eb050f4ea4c Mon Sep 17 00:00:00 2001
From: goat
Date: Thu, 2 Jan 2025 15:10:15 +0100
Subject: [PATCH 52/88] remove useless PathMap in c# projects
---
Dalamud.Injector/Dalamud.Injector.csproj | 4 ----
Dalamud/Dalamud.csproj | 4 ----
2 files changed, 8 deletions(-)
diff --git a/Dalamud.Injector/Dalamud.Injector.csproj b/Dalamud.Injector/Dalamud.Injector.csproj
index 1ff29ea66..9cc063916 100644
--- a/Dalamud.Injector/Dalamud.Injector.csproj
+++ b/Dalamud.Injector/Dalamud.Injector.csproj
@@ -45,10 +45,6 @@
DEBUG;TRACE
-
- $(MSBuildProjectDirectory)\
- $(AppOutputBase)=C:\goatsoft\companysecrets\injector\
-
IDE0003;IDE0044;IDE1006;CS1591;CS1701;CS1702
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index d869f76ba..89db02fa0 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -47,10 +47,6 @@
DEBUG;TRACE
-
- $(MSBuildProjectDirectory)\
- $(AppOutputBase)=C:\goatsoft\companysecrets\dalamud\
-
IDE0002;IDE0003;IDE1006;IDE0044;CA1822;CS1591;CS1701;CS1702
From d22ff8fad8d00acb1b1e106053cda1e4fad52a17 Mon Sep 17 00:00:00 2001
From: goat
Date: Thu, 2 Jan 2025 17:21:57 +0100
Subject: [PATCH 53/88] don't save windows that haven't changed
---
.../Interface/Windowing/Persistence/PresetModel.cs | 8 ++++++++
.../Windowing/Persistence/WindowSystemPersistence.cs | 12 +++++++++++-
2 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/Dalamud/Interface/Windowing/Persistence/PresetModel.cs b/Dalamud/Interface/Windowing/Persistence/PresetModel.cs
index db91bad8a..f7910e0b2 100644
--- a/Dalamud/Interface/Windowing/Persistence/PresetModel.cs
+++ b/Dalamud/Interface/Windowing/Persistence/PresetModel.cs
@@ -49,5 +49,13 @@ internal class PresetModel
///
[JsonProperty("a")]
public float? Alpha { get; set; }
+
+ ///
+ /// Gets a value indicating whether this preset is in the default state.
+ ///
+ public bool IsDefault =>
+ !this.IsPinned &&
+ !this.IsClickThrough &&
+ !this.Alpha.HasValue;
}
}
diff --git a/Dalamud/Interface/Windowing/Persistence/WindowSystemPersistence.cs b/Dalamud/Interface/Windowing/Persistence/WindowSystemPersistence.cs
index 8b884b0e5..a64928003 100644
--- a/Dalamud/Interface/Windowing/Persistence/WindowSystemPersistence.cs
+++ b/Dalamud/Interface/Windowing/Persistence/WindowSystemPersistence.cs
@@ -41,7 +41,17 @@ internal class WindowSystemPersistence : IServiceType
/// The preset window instance.
public void SaveWindow(uint id, PresetModel.PresetWindow window)
{
- this.ActivePreset.Windows[id] = window;
+ // If the window is in the default state, don't save it to avoid saving every possible window
+ // if the user has not customized anything.
+ if (window.IsDefault)
+ {
+ this.ActivePreset.Windows.Remove(id);
+ }
+ else
+ {
+ this.ActivePreset.Windows[id] = window;
+ }
+
this.config.QueueSave();
}
}
From e0eca2ac70e8c28679de62849b9fac76062155e7 Mon Sep 17 00:00:00 2001
From: goat
Date: Thu, 2 Jan 2025 17:29:49 +0100
Subject: [PATCH 54/88] don't auto-enable imgui asserts for now, until we have
better tracing
---
Dalamud/Plugin/Internal/PluginManager.cs | 89 ++++++++++++------------
1 file changed, 45 insertions(+), 44 deletions(-)
diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs
index b70b74b03..7a05a7549 100644
--- a/Dalamud/Plugin/Internal/PluginManager.cs
+++ b/Dalamud/Plugin/Internal/PluginManager.cs
@@ -53,7 +53,7 @@ internal class PluginManager : IInternalDisposableService
private readonly object pluginListLock = new();
private readonly DirectoryInfo pluginDirectory;
private readonly BannedPlugin[]? bannedPlugins;
-
+
private readonly List installedPluginsList = new();
private readonly List availablePluginsList = new();
private readonly List updatablePluginsList = new();
@@ -207,7 +207,7 @@ internal class PluginManager : IInternalDisposableService
}
}
}
-
+
///
/// Gets a copy of the list of all plugins with an available update.
///
@@ -261,7 +261,7 @@ internal class PluginManager : IInternalDisposableService
/// Gets or sets a value indicating whether banned plugins will be loaded.
///
public bool LoadBannedPlugins { get; set; }
-
+
///
/// Gets a tracker for plugins that are loading at startup, used to display information to the user.
///
@@ -479,7 +479,7 @@ internal class PluginManager : IInternalDisposableService
Log.Error("No DLL found for plugin at {Path}", versionDir.FullName);
continue;
}
-
+
var manifestFile = LocalPluginManifest.GetManifestFile(dllFile);
if (!manifestFile.Exists)
{
@@ -506,7 +506,7 @@ internal class PluginManager : IInternalDisposableService
}
this.configuration.QueueSave();
-
+
if (versionsDefs.Count == 0)
{
Log.Verbose("No versions found for plugin: {Name}", pluginDir.Name);
@@ -552,7 +552,7 @@ internal class PluginManager : IInternalDisposableService
Log.Error("DLL at {DllPath} has no manifest, this is no longer valid", dllFile.FullName);
continue;
}
-
+
var manifest = LocalPluginManifest.Load(manifestFile);
if (manifest == null)
{
@@ -761,7 +761,7 @@ internal class PluginManager : IInternalDisposableService
.SelectMany(repo => repo.PluginMaster)
.Where(this.IsManifestEligible)
.Where(IsManifestVisible));
-
+
if (notify)
{
this.NotifyAvailablePluginsChanged();
@@ -783,7 +783,7 @@ internal class PluginManager : IInternalDisposableService
{
if (!setting.IsEnabled)
continue;
-
+
Log.Verbose("Scanning dev plugins at {Path}", setting.Path);
if (File.Exists(setting.Path))
@@ -810,7 +810,7 @@ internal class PluginManager : IInternalDisposableService
Log.Error("DLL at {DllPath} has no manifest, this is no longer valid", dllFile.FullName);
continue;
}
-
+
var manifest = LocalPluginManifest.Load(manifestFile);
if (manifest == null)
{
@@ -854,7 +854,7 @@ internal class PluginManager : IInternalDisposableService
var stream = await this.DownloadPluginAsync(repoManifest, useTesting);
return await this.InstallPluginInternalAsync(repoManifest, useTesting, reason, stream, inheritedWorkingPluginId);
}
-
+
///
/// Remove a plugin.
///
@@ -1048,7 +1048,7 @@ internal class PluginManager : IInternalDisposableService
Status = PluginUpdateStatus.StatusKind.Success,
HasChangelog = !metadata.UpdateManifest.Changelog.IsNullOrWhitespace(),
};
-
+
// Check if this plugin is already up to date (=> AvailablePluginUpdate was stale)
lock (this.installedPluginsList)
{
@@ -1075,7 +1075,7 @@ internal class PluginManager : IInternalDisposableService
updateStatus.Status = PluginUpdateStatus.StatusKind.FailedDownload;
return updateStatus;
}
-
+
// Unload if loaded
if (plugin.State is PluginState.Loaded or PluginState.LoadError or PluginState.DependencyResolutionFailed)
{
@@ -1305,7 +1305,7 @@ internal class PluginManager : IInternalDisposableService
{
if (serviceType == typeof(PluginManager))
continue;
-
+
// Scoped plugin services lifetime is tied to their scopes. They go away when LocalPlugin goes away.
// Nonetheless, their direct dependencies must be considered.
if (serviceType.GetServiceKind() == ServiceManager.ServiceKind.ScopedService)
@@ -1313,19 +1313,19 @@ internal class PluginManager : IInternalDisposableService
var typeAsServiceT = ServiceHelpers.GetAsService(serviceType);
var dependencies = ServiceHelpers.GetDependencies(typeAsServiceT, false);
ServiceManager.Log.Verbose("Found dependencies of scoped plugin service {Type} ({Cnt})", serviceType.FullName!, dependencies!.Count);
-
+
foreach (var scopedDep in dependencies)
{
if (scopedDep == typeof(PluginManager))
throw new Exception("Scoped plugin services cannot depend on PluginManager.");
-
+
ServiceManager.Log.Verbose("PluginManager MUST depend on {Type} via {BaseType}", scopedDep.FullName!, serviceType.FullName!);
yield return scopedDep;
}
continue;
}
-
+
var pluginInterfaceAttribute = serviceType.GetCustomAttribute(true);
if (pluginInterfaceAttribute == null)
continue;
@@ -1336,12 +1336,12 @@ internal class PluginManager : IInternalDisposableService
}
///
- /// Check if there are any inconsistencies with our plugins, their IDs, and our profiles.
+ /// Check if there are any inconsistencies with our plugins, their IDs, and our profiles.
///
private void ParanoiaValidatePluginsAndProfiles()
{
var seenIds = new List();
-
+
foreach (var installedPlugin in this.InstalledPlugins)
{
if (installedPlugin.EffectiveWorkingPluginId == Guid.Empty)
@@ -1352,13 +1352,13 @@ internal class PluginManager : IInternalDisposableService
throw new Exception(
$"{(installedPlugin is LocalDevPlugin ? "DevPlugin" : "Plugin")} '{installedPlugin.Manifest.InternalName}' has a duplicate WorkingPluginId '{installedPlugin.EffectiveWorkingPluginId}'");
}
-
+
seenIds.Add(installedPlugin.EffectiveWorkingPluginId);
}
-
+
this.profileManager.ParanoiaValidateProfiles();
}
-
+
private async Task DownloadPluginAsync(RemotePluginManifest repoManifest, bool useTesting)
{
var downloadUrl = useTesting ? repoManifest.DownloadLinkTesting : repoManifest.DownloadLinkInstall;
@@ -1391,7 +1391,7 @@ internal class PluginManager : IInternalDisposableService
{
var version = useTesting ? repoManifest.TestingAssemblyVersion : repoManifest.AssemblyVersion;
Log.Debug($"Installing plugin {repoManifest.Name} (testing={useTesting}, version={version}, reason={reason})");
-
+
// If this plugin is in the default profile for whatever reason, delete the state
// If it was in multiple profiles and is still, the user uninstalled it and chose to keep it in there,
// or the user removed the plugin manually in which case we don't care
@@ -1425,7 +1425,7 @@ internal class PluginManager : IInternalDisposableService
// If we are doing anything other than a fresh install, not having a workingPluginId is an error that must be fixed
Debug.Assert(inheritedWorkingPluginId != null, "inheritedWorkingPluginId != null");
}
-
+
// Ensure that we have a testing opt-in for this plugin if we are installing a testing version
if (useTesting && this.configuration.PluginTestingOptIns!.All(x => x.InternalName != repoManifest.InternalName))
{
@@ -1534,7 +1534,7 @@ internal class PluginManager : IInternalDisposableService
this.NotifyinstalledPluginsListChanged();
return plugin;
}
-
+
///
/// Load a plugin.
///
@@ -1562,16 +1562,17 @@ internal class PluginManager : IInternalDisposableService
{
Log.Information($"Loading dev plugin {name}");
plugin = new LocalDevPlugin(dllFile, manifest);
-
+
// This is a dev plugin - turn ImGui asserts on by default if we haven't chosen yet
- this.configuration.ImGuiAssertsEnabledAtStartup ??= true;
+ // TODO(goat): Re-enable this when we have better tracing for what was rendering when
+ // this.configuration.ImGuiAssertsEnabledAtStartup ??= true;
}
else
{
Log.Information($"Loading plugin {name}");
plugin = new LocalPlugin(dllFile, manifest);
}
-
+
// Perform a migration from InternalName to GUIDs. The plugin should definitely have a GUID here.
// 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
@@ -1579,7 +1580,7 @@ internal class PluginManager : IInternalDisposableService
if (plugin.EffectiveWorkingPluginId == Guid.Empty)
throw new Exception("Plugin should have a WorkingPluginId at this point");
this.profileManager.MigrateProfilesToGuidsForPlugin(plugin.Manifest.InternalName, plugin.EffectiveWorkingPluginId);
-
+
var wantedByAnyProfile = false;
// Now, if this is a devPlugin, figure out if we want to load it
@@ -1595,11 +1596,11 @@ internal class PluginManager : IInternalDisposableService
// We don't know about this plugin, so we don't want to do anything here.
// The code below will take care of it and add it with the default value.
Log.Verbose("DevPlugin {Name} not wanted in default plugin", plugin.Manifest.InternalName);
-
+
// 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.EffectiveWorkingPluginId, plugin.Manifest.InternalName, false, false);
-
+
// If it is wanted by any other profile, we do want to load it.
if (wantedByAnyProfile)
loadPlugin = true;
@@ -1646,12 +1647,12 @@ internal class PluginManager : IInternalDisposableService
#pragma warning disable CS0618
var defaultState = manifest?.Disabled != true && loadPlugin;
#pragma warning restore CS0618
-
+
// 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.EffectiveWorkingPluginId, plugin.Manifest.InternalName, defaultState);
Log.Information("{Name} defaultState: {State} wantedByAnyProfile: {WantedByAny} loadPlugin: {LoadPlugin}", plugin.Manifest.InternalName, defaultState, wantedByAnyProfile, loadPlugin);
-
+
if (loadPlugin)
{
try
@@ -1735,11 +1736,11 @@ internal class PluginManager : IInternalDisposableService
private void DetectAvailablePluginUpdates()
{
Log.Debug("Starting plugin update check...");
-
+
lock (this.pluginListLock)
{
this.updatablePluginsList.Clear();
-
+
foreach (var plugin in this.installedPluginsList)
{
var installedVersion = plugin.IsTesting
@@ -1778,12 +1779,12 @@ internal class PluginManager : IInternalDisposableService
}
}
}
-
+
Log.Debug("Update check found {updateCount} available updates.", this.updatablePluginsList.Count);
}
private void NotifyAvailablePluginsChanged()
- {
+ {
this.DetectAvailablePluginUpdates();
this.OnAvailablePluginsChanged?.InvokeSafely();
@@ -1831,7 +1832,7 @@ internal class PluginManager : IInternalDisposableService
using (Timings.Start("PM Load Sync Plugins"))
{
var loadAllPlugins = Task.Run(this.LoadAllPlugins);
-
+
// We wait for all blocking services and tasks to finish before kicking off the main thread in any mode.
// This means that we don't want to block here if this stupid thing isn't enabled.
if (this.configuration.IsResumeGameAfterPluginLoad)
@@ -1850,12 +1851,12 @@ internal class PluginManager : IInternalDisposableService
Log.Error(ex, "Plugin load failed");
}
}
-
+
///
/// Class representing progress of an update operation.
///
public record PluginUpdateProgress(int PluginsProcessed, int TotalPlugins, IPluginManifest CurrentPluginManifest);
-
+
///
/// Simple class that tracks the internal names and public names of plugins that we are planning to load at startup,
/// and are still actively loading.
@@ -1865,12 +1866,12 @@ internal class PluginManager : IInternalDisposableService
private readonly Dictionary internalToPublic = new();
private readonly ConcurrentBag allInternalNames = new();
private readonly ConcurrentBag finishedInternalNames = new();
-
+
///
/// Gets a value indicating the total load progress.
///
public float Progress => (float)this.finishedInternalNames.Count / this.allInternalNames.Count;
-
+
///
/// Calculate a set of internal names that are still pending.
///
@@ -1881,7 +1882,7 @@ internal class PluginManager : IInternalDisposableService
pending.ExceptWith(this.finishedInternalNames);
return pending;
}
-
+
///
/// Track a new plugin.
///
@@ -1892,7 +1893,7 @@ internal class PluginManager : IInternalDisposableService
this.internalToPublic[internalName] = publicName;
this.allInternalNames.Add(internalName);
}
-
+
///
/// Mark a plugin as finished loading.
///
@@ -1901,7 +1902,7 @@ internal class PluginManager : IInternalDisposableService
{
this.finishedInternalNames.Add(internalName);
}
-
+
///
/// Get the public name for a given internal name.
///
From b74f4fba01dffd7f858b91e067733c55ad42c5e6 Mon Sep 17 00:00:00 2001
From: bleatbot <106497096+bleatbot@users.noreply.github.com>
Date: Fri, 3 Jan 2025 16:07:57 +0100
Subject: [PATCH 55/88] Update ClientStructs (#2151)
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 cc98a564d..7ba7ab4fd 160000
--- a/lib/FFXIVClientStructs
+++ b/lib/FFXIVClientStructs
@@ -1 +1 @@
-Subproject commit cc98a564d0787813d4be082bf75f5bb98e0ed12f
+Subproject commit 7ba7ab4fdd90b05631807ebdaeec9613f33397bd
From 6d0c9d4f4a40b297506cfbc88361e2126d36c55e Mon Sep 17 00:00:00 2001
From: goat
Date: Fri, 3 Jan 2025 17:00:03 +0100
Subject: [PATCH 56/88] build: 11.0.5.0
---
Dalamud/Dalamud.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index 89db02fa0..2297355a1 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -10,7 +10,7 @@
XIV Launcher addon framework
- 11.0.4.0
+ 11.0.5.0
$(DalamudVersion)
$(DalamudVersion)
$(DalamudVersion)
From e999a8f678ead9cdd48d7df6e63f24f7ef6e7f16 Mon Sep 17 00:00:00 2001
From: wolfcomp <4028289+wolfcomp@users.noreply.github.com>
Date: Fri, 3 Jan 2025 17:57:34 +0100
Subject: [PATCH 57/88] Add timezone offset to system time in crash log (#2142)
---
DalamudCrashHandler/DalamudCrashHandler.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/DalamudCrashHandler/DalamudCrashHandler.cpp b/DalamudCrashHandler/DalamudCrashHandler.cpp
index 4b1d4a6e5..62ccdd20a 100644
--- a/DalamudCrashHandler/DalamudCrashHandler.cpp
+++ b/DalamudCrashHandler/DalamudCrashHandler.cpp
@@ -941,7 +941,7 @@ int main() {
log << std::format(L"Dump at: {}", dumpPath.wstring()) << std::endl;
else
log << std::format(L"Dump error: {}", dumpError) << std::endl;
- log << L"System Time: " << std::chrono::system_clock::now() << std::endl;
+ log << std::format(L"System Time: {0:%F} {0:%T} {0:%Ez}", std::chrono::system_clock::now()) << std::endl;
log << L"\n" << stackTrace << std::endl;
if (pProgressDialog)
From a690ccbeef68189282e036743c4307f877a89396 Mon Sep 17 00:00:00 2001
From: goat
Date: Fri, 3 Jan 2025 18:32:34 +0100
Subject: [PATCH 58/88] build: 11.0.5.1
---
Dalamud/Dalamud.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index 2297355a1..c4f99ec34 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -10,7 +10,7 @@
XIV Launcher addon framework
- 11.0.5.0
+ 11.0.5.1
$(DalamudVersion)
$(DalamudVersion)
$(DalamudVersion)
From 27b6dfcbea30c94ff65361883f61cf9bd3de2b9f Mon Sep 17 00:00:00 2001
From: goat
Date: Thu, 9 Jan 2025 21:58:23 +0100
Subject: [PATCH 59/88] don't allow window additions for multi-monitor windows
---
Dalamud/Interface/Windowing/Window.cs | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/Dalamud/Interface/Windowing/Window.cs b/Dalamud/Interface/Windowing/Window.cs
index 6219de852..79bb63685 100644
--- a/Dalamud/Interface/Windowing/Window.cs
+++ b/Dalamud/Interface/Windowing/Window.cs
@@ -378,6 +378,16 @@ public abstract class Window
{
ImGuiNativeAdditions.igCustom_WindowSetInheritNoInputs(this.internalIsClickthrough);
+ // Not supported yet on non-main viewports
+ if ((this.internalIsPinned || this.internalIsClickthrough || this.internalAlpha.HasValue) &&
+ ImGui.GetWindowViewport().ID != ImGui.GetMainViewport().ID)
+ {
+ this.internalAlpha = null;
+ this.internalIsPinned = false;
+ this.internalIsClickthrough = false;
+ this.presetDirty = true;
+ }
+
// Draw the actual window contents
try
{
From da8be031248940f8bc8ee6bb178bd4c491d60a65 Mon Sep 17 00:00:00 2001
From: goat
Date: Thu, 9 Jan 2025 22:00:53 +0100
Subject: [PATCH 60/88] don't log imgui asserts unless we've shown them this
session
---
Dalamud/Interface/Internal/Asserts/AssertHandler.cs | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/Dalamud/Interface/Internal/Asserts/AssertHandler.cs b/Dalamud/Interface/Internal/Asserts/AssertHandler.cs
index c1dc12206..376aaed5b 100644
--- a/Dalamud/Interface/Internal/Asserts/AssertHandler.cs
+++ b/Dalamud/Interface/Internal/Asserts/AssertHandler.cs
@@ -24,6 +24,8 @@ internal class AssertHandler : IDisposable
// Store callback to avoid it from being GC'd
private readonly AssertCallbackDelegate callback;
+ private bool everShownAssertThisSession = false;
+
///
/// Initializes a new instance of the class.
///
@@ -76,6 +78,10 @@ internal class AssertHandler : IDisposable
if (this.ignoredAsserts.Contains(key))
return;
+ // Don't log unless we've ever shown an assert this session
+ if (!this.ShowAsserts && !this.everShownAssertThisSession)
+ return;
+
Lazy stackTrace = new(() => new StackTrace(3).ToString());
if (!this.EnableVerboseLogging)
@@ -110,6 +116,8 @@ internal class AssertHandler : IDisposable
if (!this.ShowAsserts)
return;
+ this.everShownAssertThisSession = true;
+
string? GetRepoUrl()
{
// TODO: implot, imguizmo?
From a656fefb2bf349a4073717c8c2219abded095b2b Mon Sep 17 00:00:00 2001
From: KazWolfe
Date: Thu, 9 Jan 2025 13:01:46 -0800
Subject: [PATCH 61/88] feat: Allow /xldev to disable Safe Mode (#2166)
- Adds new menu item to /xldev to disable Safe Mode, allowing users to load plugins again.
- Safe mode cannot be re-enabled once disabled.
- Add new ModuleLog.Create for eventual ILogger magic
- Make safe mode writable
- Remove redundant check in CheckPolicy
---
.../Interface/Internal/DalamudInterface.cs | 5 ++++
Dalamud/Logging/Internal/ModuleLog.cs | 25 ++++++++++++++++++-
Dalamud/Plugin/Internal/PluginManager.cs | 6 ++---
Dalamud/Plugin/Internal/Types/LocalPlugin.cs | 15 +++++------
4 files changed, 38 insertions(+), 13 deletions(-)
diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs
index 0381164c9..f3f2564af 100644
--- a/Dalamud/Interface/Internal/DalamudInterface.cs
+++ b/Dalamud/Interface/Internal/DalamudInterface.cs
@@ -1012,6 +1012,11 @@ internal class DalamudInterface : IInternalDisposableService
pluginManager.LoadBannedPlugins = !pluginManager.LoadBannedPlugins;
}
+ if (pluginManager.SafeMode && ImGui.MenuItem("Disable Safe Mode"))
+ {
+ pluginManager.SafeMode = false;
+ }
+
ImGui.Separator();
ImGui.MenuItem("API Level:" + PluginManager.DalamudApiLevel, false);
ImGui.MenuItem("Loaded plugins:" + pluginManager.InstalledPlugins.Count(), false);
diff --git a/Dalamud/Logging/Internal/ModuleLog.cs b/Dalamud/Logging/Internal/ModuleLog.cs
index bcbb6e2b1..bb5af4ffe 100644
--- a/Dalamud/Logging/Internal/ModuleLog.cs
+++ b/Dalamud/Logging/Internal/ModuleLog.cs
@@ -1,5 +1,6 @@
using Serilog;
using Serilog.Core;
+using Serilog.Core.Enrichers;
using Serilog.Events;
namespace Dalamud.Logging.Internal;
@@ -11,7 +12,7 @@ public class ModuleLog
{
private readonly string moduleName;
private readonly ILogger moduleLogger;
-
+
// FIXME (v9): Deprecate this class in favor of using contextualized ILoggers with proper formatting.
// We can keep this class around as a Serilog helper, but ModuleLog should no longer be a returned
// type, instead returning a (prepared) ILogger appropriately.
@@ -27,6 +28,28 @@ public class ModuleLog
this.moduleLogger = Log.ForContext("Dalamud.ModuleName", this.moduleName);
}
+ ///
+ /// Initializes a new instance of the class.
+ /// This class will properly attach SourceContext and other attributes per Serilog standards.
+ ///
+ /// The type of the class this logger is for.
+ public ModuleLog(Type type)
+ {
+ this.moduleName = type.Name;
+ this.moduleLogger = Log.ForContext(
+ [
+ new PropertyEnricher(Constants.SourceContextPropertyName, type.FullName),
+ new PropertyEnricher("Dalamud.ModuleName", this.moduleName)
+ ]);
+ }
+
+ ///
+ /// Helper method to create a new instance based on a type.
+ ///
+ /// The class to create this ModuleLog for.
+ /// Returns a ModuleLog with name set.
+ internal static ModuleLog Create() => new(typeof(T));
+
///
/// Log a templated verbose message to the in-game debug log.
///
diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs
index 7a05a7549..5cab004ed 100644
--- a/Dalamud/Plugin/Internal/PluginManager.cs
+++ b/Dalamud/Plugin/Internal/PluginManager.cs
@@ -48,7 +48,7 @@ internal class PluginManager : IInternalDisposableService
///
public const int PluginWaitBeforeFreeDefault = 1000; // upped from 500ms, seems more stable
- private static readonly ModuleLog Log = new("PLUGINM");
+ private static readonly ModuleLog Log = ModuleLog.Create();
private readonly object pluginListLock = new();
private readonly DirectoryInfo pluginDirectory;
@@ -243,9 +243,9 @@ internal class PluginManager : IInternalDisposableService
public bool ReposReady { get; private set; }
///
- /// Gets a value indicating whether the plugin manager started in safe mode.
+ /// Gets or sets a value indicating whether the plugin manager started in safe mode.
///
- public bool SafeMode { get; init; }
+ public bool SafeMode { get; set; }
///
/// Gets the object used when initializing plugins.
diff --git a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs
index 43bba0a5b..a86a39905 100644
--- a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs
+++ b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs
@@ -30,7 +30,7 @@ internal class LocalPlugin : IAsyncDisposable
#pragma warning disable SA1401
protected LocalPluginManifest manifest;
#pragma warning restore SA1401
-
+
private static readonly ModuleLog Log = new("LOCALPLUGIN");
private readonly FileInfo manifestFile;
@@ -314,7 +314,7 @@ internal class LocalPlugin : IAsyncDisposable
this.State = PluginState.Loading;
Log.Information($"Loading {this.DllFile.Name}");
-
+
this.EnsureLoader();
if (this.DllFile.DirectoryName != null &&
@@ -413,7 +413,7 @@ internal class LocalPlugin : IAsyncDisposable
if (ex is not InvalidPluginOperationException)
this.State = PluginState.LoadError;
- // If a precondition fails, don't record it as an error, as it isn't really.
+ // If a precondition fails, don't record it as an error, as it isn't really.
if (ex is PluginPreconditionFailedException)
Log.Warning(ex.Message);
else
@@ -510,9 +510,6 @@ internal class LocalPlugin : IAsyncDisposable
var startInfo = Service.Get().StartInfo;
var manager = Service.Get();
- if (startInfo.NoLoadPlugins)
- return false;
-
if (startInfo.NoLoadThirdPartyPlugins && this.manifest.IsThirdParty)
return false;
@@ -556,7 +553,7 @@ internal class LocalPlugin : IAsyncDisposable
///
/// Why it should be saved.
protected void SaveManifest(string reason) => this.manifest.Save(this.manifestFile, reason);
-
+
///
/// Called before a plugin is reloaded.
///
@@ -595,7 +592,7 @@ internal class LocalPlugin : IAsyncDisposable
// but plugins may load other versions of assemblies that Dalamud depends on.
config.SharedAssemblies.Add((typeof(EntryPoint).Assembly.GetName(), false));
config.SharedAssemblies.Add((typeof(Common.DalamudStartInfo).Assembly.GetName(), false));
-
+
// Pin Lumina since we expose it as an API surface. Before anyone removes this again, please see #1598.
// Changes to Lumina should be upstreamed if feasible, and if there is a desire to re-add unpinned Lumina we
// will need to put this behind some kind of feature flag somewhere.
@@ -607,7 +604,7 @@ internal class LocalPlugin : IAsyncDisposable
{
if (this.loader != null)
return;
-
+
try
{
this.loader = PluginLoader.CreateFromAssemblyFile(this.DllFile.FullName, SetupLoaderConfig);
From bed591d890f5be69b5178d5f8d12df75bfe636fe Mon Sep 17 00:00:00 2001
From: KazWolfe
Date: Thu, 9 Jan 2025 13:11:41 -0800
Subject: [PATCH 62/88] fix: Forcefully load stacktrace if assert UI is shown
(#2164)
- Add DiagnosticUtil to automatically filter out the "boring" stack entries.
Co-authored-by: goat <16760685+goaaats@users.noreply.github.com>
---
.../Internal/Asserts/AssertHandler.cs | 5 ++-
Dalamud/Utility/DiagnosticUtil.cs | 32 +++++++++++++++++++
2 files changed, 36 insertions(+), 1 deletion(-)
create mode 100644 Dalamud/Utility/DiagnosticUtil.cs
diff --git a/Dalamud/Interface/Internal/Asserts/AssertHandler.cs b/Dalamud/Interface/Internal/Asserts/AssertHandler.cs
index 376aaed5b..56050cdfb 100644
--- a/Dalamud/Interface/Internal/Asserts/AssertHandler.cs
+++ b/Dalamud/Interface/Internal/Asserts/AssertHandler.cs
@@ -82,7 +82,7 @@ internal class AssertHandler : IDisposable
if (!this.ShowAsserts && !this.everShownAssertThisSession)
return;
- Lazy stackTrace = new(() => new StackTrace(3).ToString());
+ Lazy stackTrace = new(() => DiagnosticUtil.GetUsefulTrace(new StackTrace()).ToString());
if (!this.EnableVerboseLogging)
{
@@ -133,6 +133,9 @@ internal class AssertHandler : IDisposable
return $"https://github.com/{userName}/{repoName}/blob/{branch}/{fileName}#L{line}";
}
+ // grab the stack trace now that we've decided to show UI.
+ _ = stackTrace.Value;
+
var gitHubUrl = GetRepoUrl();
var showOnGitHubButton = new TaskDialogButton
{
diff --git a/Dalamud/Utility/DiagnosticUtil.cs b/Dalamud/Utility/DiagnosticUtil.cs
new file mode 100644
index 000000000..9c9718c4e
--- /dev/null
+++ b/Dalamud/Utility/DiagnosticUtil.cs
@@ -0,0 +1,32 @@
+using System.Diagnostics;
+using System.Linq;
+
+namespace Dalamud.Utility;
+
+///
+/// A set of utilities for diagnostics.
+///
+public static class DiagnosticUtil
+{
+ private static readonly string[] IgnoredNamespaces = [
+ nameof(System),
+ nameof(ImGuiNET.ImGuiNative)
+ ];
+
+ ///
+ /// Gets a stack trace that filters out irrelevant frames.
+ ///
+ /// The source stacktrace to filter.
+ /// Returns a stack trace with "extra" frames removed.
+ public static StackTrace GetUsefulTrace(StackTrace source)
+ {
+ var frames = source.GetFrames().SkipWhile(
+ f =>
+ {
+ var frameNs = f.GetMethod()?.DeclaringType?.Namespace;
+ return frameNs == null || IgnoredNamespaces.Any(i => frameNs.StartsWith(i, true, null));
+ });
+
+ return new StackTrace(frames);
+ }
+}
From 0b9a2fd9c8752a35ebe1a6d091f8e338c1a026df Mon Sep 17 00:00:00 2001
From: bleatbot <106497096+bleatbot@users.noreply.github.com>
Date: Thu, 9 Jan 2025 22:12:21 +0100
Subject: [PATCH 63/88] Update ClientStructs (#2163)
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 7ba7ab4fd..9543f553e 160000
--- a/lib/FFXIVClientStructs
+++ b/lib/FFXIVClientStructs
@@ -1 +1 @@
-Subproject commit 7ba7ab4fdd90b05631807ebdaeec9613f33397bd
+Subproject commit 9543f553e609f1682451c62c0ffcf5303359cf24
From f2c132c7d8723c93b53008afa0866076136fb44d Mon Sep 17 00:00:00 2001
From: Haselnussbomber
Date: Thu, 9 Jan 2025 22:15:14 +0100
Subject: [PATCH 64/88] Allow setting a DisplayOrder on commands (#2162)
* Allow setting a DisplayOrder on commands
* Linq on demand
* Sort commands in /help alphabetically
* note default in xmldoc
---------
Co-authored-by: goat <16760685+goaaats@users.noreply.github.com>
---
Dalamud/Game/Command/CommandInfo.cs | 10 +++++++++-
Dalamud/Interface/Internal/DalamudCommands.cs | 2 +-
.../Windows/PluginInstaller/PluginInstallerWindow.cs | 7 ++++---
3 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/Dalamud/Game/Command/CommandInfo.cs b/Dalamud/Game/Command/CommandInfo.cs
index 8aed817d0..16462a831 100644
--- a/Dalamud/Game/Command/CommandInfo.cs
+++ b/Dalamud/Game/Command/CommandInfo.cs
@@ -11,7 +11,7 @@ public interface IReadOnlyCommandInfo
/// The command itself.
/// The arguments supplied to the command, ready for parsing.
public delegate void HandlerDelegate(string command, string arguments);
-
+
///
/// Gets a which will be called when the command is dispatched.
///
@@ -26,6 +26,11 @@ public interface IReadOnlyCommandInfo
/// Gets a value indicating whether if this command should be shown in the help output.
///
bool ShowInHelp { get; }
+
+ ///
+ /// Gets the display order of this command. Defaults to alphabetical ordering.
+ ///
+ int DisplayOrder { get; }
}
///
@@ -51,4 +56,7 @@ public sealed class CommandInfo : IReadOnlyCommandInfo
///
public bool ShowInHelp { get; set; } = true;
+
+ ///
+ public int DisplayOrder { get; set; } = -1;
}
diff --git a/Dalamud/Interface/Internal/DalamudCommands.cs b/Dalamud/Interface/Internal/DalamudCommands.cs
index 00997c1d5..636f71bfa 100644
--- a/Dalamud/Interface/Internal/DalamudCommands.cs
+++ b/Dalamud/Interface/Internal/DalamudCommands.cs
@@ -178,7 +178,7 @@ internal class DalamudCommands : IServiceType
if (arguments.IsNullOrWhitespace())
{
chatGui.Print(Loc.Localize("DalamudCmdHelpAvailable", "Available commands:"));
- foreach (var cmd in commandManager.Commands)
+ foreach (var cmd in commandManager.Commands.OrderBy(cInfo => cInfo.Key))
{
if (!cmd.Value.ShowInHelp)
continue;
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
index 4e60d4be8..3abb1bb39 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
@@ -2762,13 +2762,14 @@ internal class PluginInstallerWindow : Window, IDisposable
var commands = commandManager.Commands
.Where(cInfo =>
cInfo.Value is { ShowInHelp: true } &&
- commandManager.GetHandlerAssemblyName(cInfo.Key, cInfo.Value) == plugin.Manifest.InternalName)
- .ToArray();
+ commandManager.GetHandlerAssemblyName(cInfo.Key, cInfo.Value) == plugin.Manifest.InternalName);
if (commands.Any())
{
ImGui.Dummy(ImGuiHelpers.ScaledVector2(10f, 10f));
- foreach (var command in commands)
+ foreach (var command in commands
+ .OrderBy(cInfo => cInfo.Value.DisplayOrder)
+ .ThenBy(cInfo => cInfo.Key))
{
ImGuiHelpers.SafeTextWrapped($"{command.Key} → {command.Value.HelpMessage}");
}
From d932f2f06e7ac4585bc300c7d31abcb60b58302b Mon Sep 17 00:00:00 2001
From: srkizer
Date: Sat, 11 Jan 2025 01:52:54 +0900
Subject: [PATCH 65/88] fix: apply scale to TSM entry (#2169)
---
.../Internal/Windows/TitleScreenMenuWindow.cs | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs b/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs
index 979f68bf8..ce8c192a4 100644
--- a/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs
@@ -11,7 +11,6 @@ using Dalamud.Game.ClientState;
using Dalamud.Game.Gui;
using Dalamud.Game.Text;
using Dalamud.Interface.Animation.EasingFunctions;
-using Dalamud.Interface.ImGuiSeStringRenderer;
using Dalamud.Interface.ManagedFontAtlas;
using Dalamud.Interface.ManagedFontAtlas.Internals;
using Dalamud.Interface.Textures.TextureWraps;
@@ -398,9 +397,14 @@ internal class TitleScreenMenuWindow : Window, IDisposable
// Drop shadow
ImGui.SetCursorPos(cursor);
- var renderStyle = default(SeStringDrawParams);
- renderStyle.FontSize = TargetFontSizePx;
- ImGuiHelpers.CompileSeStringWrapped($"{entry.Name}", renderStyle);
+ ImGuiHelpers.SeStringWrapped(
+ ReadOnlySeString.FromText(entry.Name),
+ new()
+ {
+ FontSize = TargetFontSizePx * ImGui.GetIO().FontGlobalScale,
+ Edge = true,
+ Shadow = true,
+ });
if (overrideAlpha)
{
From d7279f5f216a4f4f362d01027dc4b624b126dab1 Mon Sep 17 00:00:00 2001
From: goat
Date: Fri, 10 Jan 2025 19:35:54 +0100
Subject: [PATCH 66/88] don't build cimgui components if we're building for
docs
---
build/DalamudBuild.cs | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/build/DalamudBuild.cs b/build/DalamudBuild.cs
index 6340c36fa..c616dd03e 100644
--- a/build/DalamudBuild.cs
+++ b/build/DalamudBuild.cs
@@ -71,6 +71,10 @@ public class DalamudBuild : NukeBuild
Target CompileCImGui => _ => _
.Executes(() =>
{
+ // Not necessary, and does not build on Linux
+ if (IsDocsBuild)
+ return;
+
MSBuildTasks.MSBuild(s => s
.SetTargetPath(CImGuiProjectFile)
.SetConfiguration(Configuration)
@@ -80,6 +84,10 @@ public class DalamudBuild : NukeBuild
Target CompileCImPlot => _ => _
.Executes(() =>
{
+ // Not necessary, and does not build on Linux
+ if (IsDocsBuild)
+ return;
+
MSBuildTasks.MSBuild(s => s
.SetTargetPath(CImPlotProjectFile)
.SetConfiguration(Configuration)
@@ -89,6 +97,10 @@ public class DalamudBuild : NukeBuild
Target CompileCImGuizmo => _ => _
.Executes(() =>
{
+ // Not necessary, and does not build on Linux
+ if (IsDocsBuild)
+ return;
+
MSBuildTasks.MSBuild(s => s
.SetTargetPath(CImGuizmoProjectFile)
.SetConfiguration(Configuration)
From d779408fdcbd99b492814cb7fb5d33adcc97fae2 Mon Sep 17 00:00:00 2001
From: goat
Date: Fri, 10 Jan 2025 19:57:08 +0100
Subject: [PATCH 67/88] don't set IsDocsBuild flag on project
---
build/DalamudBuild.cs | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/build/DalamudBuild.cs b/build/DalamudBuild.cs
index c616dd03e..67a812916 100644
--- a/build/DalamudBuild.cs
+++ b/build/DalamudBuild.cs
@@ -126,12 +126,12 @@ public class DalamudBuild : NukeBuild
// We need to emit compiler generated files for the docs build, since docfx can't run generators directly
// TODO: This fails every build after this because of redefinitions...
- if (IsDocsBuild)
- {
- Log.Warning("Building for documentation, emitting compiler generated files. This can cause issues on Windows due to path-length limitations");
- s = s
- .SetProperty("IsDocsBuild", "true");
- }
+ // if (IsDocsBuild)
+ // {
+ // Log.Warning("Building for documentation, emitting compiler generated files. This can cause issues on Windows due to path-length limitations");
+ // s = s
+ // .SetProperty("IsDocsBuild", "true");
+ // }
return s;
});
From 56acb7dead5bd4a41d25a4a34c84f6dc8cfa66f5 Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 20 Jan 2025 22:03:51 +0100
Subject: [PATCH 68/88] build: 11.0.5.2
---
Dalamud/Dalamud.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index c4f99ec34..5ca193c08 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -10,7 +10,7 @@
XIV Launcher addon framework
- 11.0.5.1
+ 11.0.5.2
$(DalamudVersion)
$(DalamudVersion)
$(DalamudVersion)
From a72dc92411ee8a8f9bdc4d75058d9131b445cf59 Mon Sep 17 00:00:00 2001
From: goat
Date: Mon, 20 Jan 2025 22:11:17 +0100
Subject: [PATCH 69/88] make window config dirty when disabling clickthrough
with title bar button
---
Dalamud/Interface/Windowing/Window.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/Dalamud/Interface/Windowing/Window.cs b/Dalamud/Interface/Windowing/Window.cs
index 79bb63685..eaa3561f5 100644
--- a/Dalamud/Interface/Windowing/Window.cs
+++ b/Dalamud/Interface/Windowing/Window.cs
@@ -498,6 +498,7 @@ public abstract class Window
Click = _ =>
{
this.internalIsClickthrough = false;
+ this.presetDirty = false;
ImGui.OpenPopup(additionsPopupName);
},
Priority = int.MinValue,
From 121b3d9a003992aa47dcd0c96e717f11b3ffa052 Mon Sep 17 00:00:00 2001
From: bleatbot <106497096+bleatbot@users.noreply.github.com>
Date: Mon, 20 Jan 2025 22:26:52 +0100
Subject: [PATCH 70/88] Update ClientStructs (#2168)
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 9543f553e..d5c13c5d3 160000
--- a/lib/FFXIVClientStructs
+++ b/lib/FFXIVClientStructs
@@ -1 +1 @@
-Subproject commit 9543f553e609f1682451c62c0ffcf5303359cf24
+Subproject commit d5c13c5d35fc3721626449c10eda605183351044
From 9d2264eec3aa8f61848b411f1951f7982a10dd12 Mon Sep 17 00:00:00 2001
From: bleatbot <106497096+bleatbot@users.noreply.github.com>
Date: Tue, 21 Jan 2025 17:24:51 +0100
Subject: [PATCH 71/88] Update ClientStructs (#2173)
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 d5c13c5d3..6a34c7073 160000
--- a/lib/FFXIVClientStructs
+++ b/lib/FFXIVClientStructs
@@ -1 +1 @@
-Subproject commit d5c13c5d35fc3721626449c10eda605183351044
+Subproject commit 6a34c7073da9170ca522deca9fbb4903ce8bc3f5
From 724d14248d13ea000c45748b77f8ab0f318a092b Mon Sep 17 00:00:00 2001
From: bleatbot <106497096+bleatbot@users.noreply.github.com>
Date: Tue, 21 Jan 2025 20:22:56 +0100
Subject: [PATCH 72/88] Update ClientStructs (#2174)
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 6a34c7073..8f2c18af4 160000
--- a/lib/FFXIVClientStructs
+++ b/lib/FFXIVClientStructs
@@ -1 +1 @@
-Subproject commit 6a34c7073da9170ca522deca9fbb4903ce8bc3f5
+Subproject commit 8f2c18af4dcd225fecee2e7713a3dead48ca5011
From 6434972b7de0631e659294bbb2d19ade7eb86f86 Mon Sep 17 00:00:00 2001
From: KazWolfe
Date: Tue, 21 Jan 2025 11:55:26 -0800
Subject: [PATCH 73/88] deps: Bump Lumina to 5.6.1 (#2171)
---
Directory.Build.props | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Directory.Build.props b/Directory.Build.props
index 6ee6f4b11..354dedd60 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,7 +1,7 @@
- 5.6.0
+ 5.6.1
7.1.3
13.0.3
From af1ddf5bfb08759d88850b070893076b9872eaaf Mon Sep 17 00:00:00 2001
From: goat
Date: Tue, 21 Jan 2025 20:59:02 +0100
Subject: [PATCH 74/88] build: 11.0.5.3
---
Dalamud/Dalamud.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index 5ca193c08..d6de19de9 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -10,7 +10,7 @@
XIV Launcher addon framework
- 11.0.5.2
+ 11.0.5.3
$(DalamudVersion)
$(DalamudVersion)
$(DalamudVersion)
From 5dd097d72b65b6e471d5a9eb1176f31ad9ec0edc Mon Sep 17 00:00:00 2001
From: Lyna <19539165+Blooym@users.noreply.github.com>
Date: Thu, 6 Feb 2025 18:55:06 +0000
Subject: [PATCH 75/88] Pinning window disables close on escape key down
(#2178)
* Pinning window disables close on escape key down
* Update tooltip for window pinning
---
Dalamud/Interface/Windowing/Window.cs | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/Dalamud/Interface/Windowing/Window.cs b/Dalamud/Interface/Windowing/Window.cs
index eaa3561f5..b3a505c1d 100644
--- a/Dalamud/Interface/Windowing/Window.cs
+++ b/Dalamud/Interface/Windowing/Window.cs
@@ -6,6 +6,7 @@ using System.Numerics;
using System.Runtime.InteropServices;
using CheapLoc;
+
using Dalamud.Game.ClientState.Keys;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
@@ -15,7 +16,9 @@ using Dalamud.Interface.Windowing.Persistence;
using Dalamud.Logging.Internal;
using FFXIVClientStructs.FFXIV.Client.UI;
+
using ImGuiNET;
+
using PInvoke;
namespace Dalamud.Interface.Windowing;
@@ -429,7 +432,7 @@ public abstract class Window
}
ImGuiComponents.HelpMarker(
- Loc.Localize("WindowSystemContextActionPinHint", "Pinned windows will not move or resize when you click and drag them."));
+ Loc.Localize("WindowSystemContextActionPinHint", "Pinned windows will not move or resize when you click and drag them, nor will they close when escape is pressed."));
}
if (this.internalIsClickthrough)
@@ -521,7 +524,7 @@ public abstract class Window
this.IsFocused = ImGui.IsWindowFocused(ImGuiFocusedFlags.RootAndChildWindows);
- if (internalDrawFlags.HasFlag(WindowDrawFlags.UseFocusManagement))
+ if (internalDrawFlags.HasFlag(WindowDrawFlags.UseFocusManagement) && !this.internalIsPinned)
{
var escapeDown = Service.Get()[VirtualKey.ESCAPE];
if (escapeDown && this.IsFocused && !wasEscPressedLastFrame && this.RespectCloseHotkey)
@@ -701,7 +704,7 @@ public abstract class Window
drawList.AddCircleFilled(GetCenter(bb) + new Vector2(0.0f, -0.5f), (fontSize * 0.5f) + 1.0f, bgCol);
var offset = button.IconOffset * ImGuiHelpers.GlobalScale;
- drawList.AddText(InterfaceManager.IconFont, (float)(fontSize * 0.8), new Vector2(bb.X + offset.X, bb.Y + offset.Y), textCol, button.Icon.ToIconString());
+ drawList.AddText(InterfaceManager.IconFont, (float)(fontSize * 0.8), new Vector2(bb.X + offset.X, bb.Y + offset.Y), textCol, button.Icon.ToIconString());
if (hovered)
button.ShowTooltip?.Invoke();
From f8a5fbac39b819420598174690fb74a60e904351 Mon Sep 17 00:00:00 2001
From: bleatbot <106497096+bleatbot@users.noreply.github.com>
Date: Sat, 15 Feb 2025 20:46:21 +0100
Subject: [PATCH 76/88] Update ClientStructs (#2175)
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 8f2c18af4..4d78d23b9 160000
--- a/lib/FFXIVClientStructs
+++ b/lib/FFXIVClientStructs
@@ -1 +1 @@
-Subproject commit 8f2c18af4dcd225fecee2e7713a3dead48ca5011
+Subproject commit 4d78d23b9a3a84222795e7aaa18785dca12ae5de
From 0ada421460ceb7767a64d48e7419dbe1e05c0a30 Mon Sep 17 00:00:00 2001
From: Jackson <9527380+Jaksuhn@users.noreply.github.com>
Date: Sat, 15 Feb 2025 20:58:04 +0100
Subject: [PATCH 77/88] Expose more of `LocalPlugin` to `ExposedPlugin` (#2177)
---
Dalamud/Plugin/InstalledPluginState.cs | 68 +++++++++++++++++++++++++-
1 file changed, 67 insertions(+), 1 deletion(-)
diff --git a/Dalamud/Plugin/InstalledPluginState.cs b/Dalamud/Plugin/InstalledPluginState.cs
index 6700a1f8d..64c8e40a5 100644
--- a/Dalamud/Plugin/InstalledPluginState.cs
+++ b/Dalamud/Plugin/InstalledPluginState.cs
@@ -1,4 +1,5 @@
-using Dalamud.Plugin.Internal.Types;
+using Dalamud.Plugin.Internal.Types;
+using Dalamud.Plugin.Internal.Types.Manifest;
namespace Dalamud.Plugin;
@@ -22,6 +23,47 @@ public interface IExposedPlugin
///
bool IsLoaded { get; }
+ ///
+ /// Gets a value indicating whether this plugin's API level is out of date.
+ ///
+ bool IsOutdated { get; }
+
+ ///
+ /// Gets a value indicating whether the plugin is for testing use only.
+ ///
+ bool IsTesting { get; }
+
+ ///
+ /// Gets a value indicating whether or not this plugin is orphaned(belongs to a repo) or not.
+ ///
+ bool IsOrphaned { get; }
+
+ ///
+ /// Gets a value indicating whether or not this plugin is serviced(repo still exists, but plugin no longer does).
+ ///
+ bool IsDecommissioned { get; }
+
+ ///
+ /// Gets a value indicating whether this plugin has been banned.
+ ///
+ bool IsBanned { get; }
+
+ ///
+ /// Gets a value indicating whether this plugin is dev plugin.
+ ///
+ bool IsDev { get; }
+
+ ///
+ /// Gets a value indicating whether this manifest is associated with a plugin that was installed from a third party
+ /// repo.
+ ///
+ bool IsThirdParty { get; }
+
+ ///
+ /// Gets the plugin manifest.
+ ///
+ ILocalPluginManifest Manifest { get; }
+
///
/// Gets the version of the plugin.
///
@@ -74,6 +116,30 @@ internal sealed class ExposedPlugin(LocalPlugin plugin) : IExposedPlugin
///
public bool HasConfigUi => plugin.DalamudInterface?.LocalUiBuilder.HasConfigUi ?? false;
+ ///
+ public bool IsOutdated => plugin.IsOutdated;
+
+ ///
+ public bool IsTesting => plugin.IsTesting;
+
+ ///
+ public bool IsOrphaned => plugin.IsOrphaned;
+
+ ///
+ public bool IsDecommissioned => plugin.IsDecommissioned;
+
+ ///
+ public bool IsBanned => plugin.IsBanned;
+
+ ///
+ public bool IsDev => plugin.IsDev;
+
+ ///
+ public bool IsThirdParty => plugin.IsThirdParty;
+
+ ///
+ public ILocalPluginManifest Manifest => plugin.Manifest;
+
///
public void OpenMainUi()
{
From 03562189e4161c52037c968c471f4b3a03cbc659 Mon Sep 17 00:00:00 2001
From: goaaats
Date: Sun, 16 Feb 2025 15:34:50 +0100
Subject: [PATCH 78/88] build: 11.0.6.0
---
Dalamud/Dalamud.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index d6de19de9..21086f969 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -10,7 +10,7 @@
XIV Launcher addon framework
- 11.0.5.3
+ 11.0.6.0
$(DalamudVersion)
$(DalamudVersion)
$(DalamudVersion)
From df78a4ae04c6426810ec3d1813980e69fe1f2eed Mon Sep 17 00:00:00 2001
From: bleatbot <106497096+bleatbot@users.noreply.github.com>
Date: Tue, 25 Feb 2025 19:04:36 +0100
Subject: [PATCH 79/88] Update ClientStructs (#2179)
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 4d78d23b9..4a727b491 160000
--- a/lib/FFXIVClientStructs
+++ b/lib/FFXIVClientStructs
@@ -1 +1 @@
-Subproject commit 4d78d23b9a3a84222795e7aaa18785dca12ae5de
+Subproject commit 4a727b491721b02a4e7b9ded289f35388758394f
From 3bd380c85442a8875e516d0d957682f75a7d4fc7 Mon Sep 17 00:00:00 2001
From: goaaats
Date: Wed, 26 Feb 2025 00:06:33 +0100
Subject: [PATCH 80/88] build: 11.0.7.0
---
Dalamud/Dalamud.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index 21086f969..e30109a99 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -10,7 +10,7 @@
XIV Launcher addon framework
- 11.0.6.0
+ 11.0.7.0
$(DalamudVersion)
$(DalamudVersion)
$(DalamudVersion)
From 3340bfd205e5d5dfb1cc9181514c8ce3a1032472 Mon Sep 17 00:00:00 2001
From: goaaats
Date: Wed, 26 Feb 2025 21:09:15 +0100
Subject: [PATCH 81/88] Remove confusing comment about IDisposable behavior
from ISharedImmediateTexture, it no longer inherits from IDisposable
---
Dalamud/Interface/Textures/ISharedImmediateTexture.cs | 1 -
1 file changed, 1 deletion(-)
diff --git a/Dalamud/Interface/Textures/ISharedImmediateTexture.cs b/Dalamud/Interface/Textures/ISharedImmediateTexture.cs
index 0ceb92171..b6aa4da83 100644
--- a/Dalamud/Interface/Textures/ISharedImmediateTexture.cs
+++ b/Dalamud/Interface/Textures/ISharedImmediateTexture.cs
@@ -11,7 +11,6 @@ namespace Dalamud.Interface.Textures;
/// A texture with a backing instance of that is shared across multiple
/// requesters.
///
-/// Calling on this interface is a no-op.
/// and may stop returning the intended texture at any point.
/// Use to lock the texture for use in any thread for any duration.
///
From defa49865ccc017f5a914e2edb8bc236ff2971fa Mon Sep 17 00:00:00 2001
From: goaaats
Date: Thu, 27 Feb 2025 21:37:05 +0100
Subject: [PATCH 82/88] Fix warning
---
Dalamud/Logging/Internal/ModuleLog.cs | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/Dalamud/Logging/Internal/ModuleLog.cs b/Dalamud/Logging/Internal/ModuleLog.cs
index bb5af4ffe..00173b09d 100644
--- a/Dalamud/Logging/Internal/ModuleLog.cs
+++ b/Dalamud/Logging/Internal/ModuleLog.cs
@@ -43,13 +43,6 @@ public class ModuleLog
]);
}
- ///
- /// Helper method to create a new instance based on a type.
- ///
- /// The class to create this ModuleLog for.
- /// Returns a ModuleLog with name set.
- internal static ModuleLog Create() => new(typeof(T));
-
///
/// Log a templated verbose message to the in-game debug log.
///
@@ -183,4 +176,11 @@ public class ModuleLog
messageTemplate: $"[{this.moduleName}] {messageTemplate}",
values);
}
+
+ ///
+ /// Helper method to create a new instance based on a type.
+ ///
+ /// The class to create this ModuleLog for.
+ /// Returns a ModuleLog with name set.
+ internal static ModuleLog Create() => new(typeof(T));
}
From dd4714753871edfc07fd1c4b30cd027c43dd9449 Mon Sep 17 00:00:00 2001
From: goaaats
Date: Thu, 27 Feb 2025 21:38:06 +0100
Subject: [PATCH 83/88] Installer: if main-repo cross update is available,
adjust warning message
---
.../PluginInstaller/PluginInstallerWindow.cs | 35 +++++++++++++------
1 file changed, 24 insertions(+), 11 deletions(-)
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
index 3abb1bb39..d01063156 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
@@ -223,10 +223,11 @@ internal class PluginInstallerWindow : Window, IDisposable
IsThirdParty = 1 << 0,
HasTrouble = 1 << 1,
UpdateAvailable = 1 << 2,
- IsNew = 1 << 3,
- IsInstallableOutdated = 1 << 4,
- IsOrphan = 1 << 5,
- IsTesting = 1 << 6,
+ MainRepoCrossUpdate = 1 << 3,
+ IsNew = 1 << 4,
+ IsInstallableOutdated = 1 << 5,
+ IsOrphan = 1 << 6,
+ IsTesting = 1 << 7,
}
private enum InstalledPluginListFilter
@@ -2217,7 +2218,12 @@ internal class PluginInstallerWindow : Window, IDisposable
else if (plugin is { IsDecommissioned: true, IsThirdParty: true })
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
- ImGui.TextWrapped(Locs.PluginBody_NoServiceThird);
+
+ ImGui.TextWrapped(
+ flags.HasFlag(PluginHeaderFlags.MainRepoCrossUpdate)
+ ? Locs.PluginBody_NoServiceThirdCrossUpdate
+ : Locs.PluginBody_NoServiceThird);
+
ImGui.PopStyleColor();
}
else if (plugin != null && !plugin.CheckPolicy())
@@ -2602,7 +2608,10 @@ internal class PluginInstallerWindow : Window, IDisposable
availablePluginUpdate = null;
// Update available
- if (availablePluginUpdate != default)
+ var isMainRepoCrossUpdate = availablePluginUpdate != null &&
+ availablePluginUpdate.UpdateManifest.RepoUrl != plugin.Manifest.RepoUrl &&
+ availablePluginUpdate.UpdateManifest.RepoUrl == PluginRepository.MainRepoUrl;
+ if (availablePluginUpdate != null)
{
label += Locs.PluginTitleMod_HasUpdate;
}
@@ -2612,7 +2621,7 @@ internal class PluginInstallerWindow : Window, IDisposable
if (this.updatedPlugins != null && !plugin.IsDev)
{
var update = this.updatedPlugins.FirstOrDefault(update => update.InternalName == plugin.Manifest.InternalName);
- if (update != default)
+ if (update != null)
{
if (update.Status == PluginUpdateStatus.StatusKind.Success)
{
@@ -2640,8 +2649,8 @@ internal class PluginInstallerWindow : Window, IDisposable
trouble = true;
}
- // Orphaned
- if (plugin.IsOrphaned)
+ // Orphaned, if we don't have a cross-repo update
+ if (plugin.IsOrphaned && !isMainRepoCrossUpdate)
{
label += Locs.PluginTitleMod_OrphanedError;
trouble = true;
@@ -2670,7 +2679,7 @@ internal class PluginInstallerWindow : Window, IDisposable
string? availableChangelog = null;
var didDrawAvailableChangelogInsideCollapsible = false;
- if (availablePluginUpdate != default)
+ if (availablePluginUpdate != null)
{
availablePluginUpdateVersion =
availablePluginUpdate.UseTesting ?
@@ -2688,8 +2697,10 @@ internal class PluginInstallerWindow : Window, IDisposable
flags |= PluginHeaderFlags.IsThirdParty;
if (trouble)
flags |= PluginHeaderFlags.HasTrouble;
- if (availablePluginUpdate != default)
+ if (availablePluginUpdate != null)
flags |= PluginHeaderFlags.UpdateAvailable;
+ if (isMainRepoCrossUpdate)
+ flags |= PluginHeaderFlags.MainRepoCrossUpdate;
if (plugin.IsOrphaned)
flags |= PluginHeaderFlags.IsOrphan;
if (plugin.IsTesting)
@@ -4056,6 +4067,8 @@ internal class PluginInstallerWindow : Window, IDisposable
public static string PluginBody_NoServiceThird => Loc.Localize("InstallerNoServiceThirdPluginBody", "This plugin is no longer being serviced by its source repo. You may have to look for an updated version in another repo.");
+ public static string PluginBody_NoServiceThirdCrossUpdate => Loc.Localize("InstallerNoServiceThirdCrossUpdatePluginBody", "This plugin is no longer being serviced by its source repo. An update is available and will update it to a version from the official repository.");
+
public static string PluginBody_LoadFailed => Loc.Localize("InstallerLoadFailedPluginBody ", "This plugin failed to load. Please contact the author for more information.");
public static string PluginBody_Banned => Loc.Localize("InstallerBannedPluginBody ", "This plugin was automatically disabled due to incompatibilities and is not available.");
From cd03ef7d02ac19aebaf5da1acbc7fdadb2122e64 Mon Sep 17 00:00:00 2001
From: nil <25884226+voidstar0@users.noreply.github.com>
Date: Fri, 28 Feb 2025 20:37:58 -0500
Subject: [PATCH 84/88] fix: always scan for dev plugins when opening the
plugin installer (#2184)
* fix: scan for dev plugins on plugin installer window open
* fix: show scan dev plugins button based on plugin locations and not installed plugins
---
.../Windows/PluginInstaller/PluginInstallerWindow.cs | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
index d01063156..66f338586 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
@@ -283,6 +283,7 @@ internal class PluginInstallerWindow : Window, IDisposable
var pluginManager = Service.Get();
_ = pluginManager.ReloadPluginMastersAsync();
+ Service.Get().ScanDevPlugins();
if (!this.isSearchTextPrefilled) this.searchText = string.Empty;
this.sortKind = PluginSortKind.Alphabetical;
@@ -755,8 +756,9 @@ internal class PluginInstallerWindow : Window, IDisposable
Service.Get().OpenSettings();
}
- // If any dev plugins are installed, allow a shortcut for the /xldev menu item
- if (this.hasDevPlugins)
+ // If any dev plugin locations exist, allow a shortcut for the /xldev menu item
+ var hasDevPluginLocations = configuration.DevPluginLoadLocations.Count > 0;
+ if (hasDevPluginLocations)
{
ImGui.SameLine();
if (ImGui.Button(Locs.FooterButton_ScanDevPlugins))
From 3a9dc48c116bc73d9f1ee32bd95404be00a5774a Mon Sep 17 00:00:00 2001
From: Cytraen <60638768+Cytraen@users.noreply.github.com>
Date: Sat, 1 Mar 2025 08:38:14 -0500
Subject: [PATCH 85/88] fix: trim quotes from dev plugin before validation
(#2186)
---
.../Windows/Settings/Widgets/DevPluginsSettingsEntry.cs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs
index 4a78735f6..720d2a70f 100644
--- a/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs
+++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs
@@ -206,6 +206,7 @@ public class DevPluginsSettingsEntry : SettingsEntry
private void AddDevPlugin()
{
+ this.devPluginTempLocation = this.devPluginTempLocation.Trim('"');
if (this.devPluginLocations.Any(
r => string.Equals(r.Path, this.devPluginTempLocation, StringComparison.InvariantCultureIgnoreCase)))
{
@@ -224,7 +225,7 @@ public class DevPluginsSettingsEntry : SettingsEntry
this.devPluginLocations.Add(
new DevPluginLocationSettings
{
- Path = this.devPluginTempLocation.Replace("\"", string.Empty),
+ Path = this.devPluginTempLocation,
IsEnabled = true,
});
this.devPluginLocationsChanged = true;
From e6017f96c09b8cde20e02371914ec25cfa989ef7 Mon Sep 17 00:00:00 2001
From: Cytraen <60638768+Cytraen@users.noreply.github.com>
Date: Sat, 1 Mar 2025 08:39:13 -0500
Subject: [PATCH 86/88] fix: only enable ImGui asserts when adding a valid dev
plugin path (#2185)
---
.../Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs
index 720d2a70f..4c5dc8b83 100644
--- a/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs
+++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs
@@ -219,6 +219,7 @@ public class DevPluginsSettingsEntry : SettingsEntry
"DalamudDevPluginInvalid",
"The entered value is not a valid path to a potential Dev Plugin.\nDid you mean to enter it as a custom plugin repository in the fields below instead?");
Task.Delay(5000).ContinueWith(t => this.devPluginLocationAddError = string.Empty);
+ return;
}
else
{
From d255a8ff277a3e1c16b9d603cf8aea73c681c338 Mon Sep 17 00:00:00 2001
From: bleatbot <106497096+bleatbot@users.noreply.github.com>
Date: Tue, 4 Mar 2025 17:32:34 +0100
Subject: [PATCH 87/88] Update ClientStructs (#2181)
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 4a727b491..484b1b588 160000
--- a/lib/FFXIVClientStructs
+++ b/lib/FFXIVClientStructs
@@ -1 +1 @@
-Subproject commit 4a727b491721b02a4e7b9ded289f35388758394f
+Subproject commit 484b1b588be5e685855392f090ec9e3eea7b3a71
From 01b3a5428e372e02dbe3c271a918e45055d32f67 Mon Sep 17 00:00:00 2001
From: goaaats
Date: Tue, 4 Mar 2025 20:25:47 +0100
Subject: [PATCH 88/88] build: 11.0.8.0
---
Dalamud/Dalamud.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index e30109a99..b24eb07ed 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -10,7 +10,7 @@
XIV Launcher addon framework
- 11.0.7.0
+ 11.0.8.0
$(DalamudVersion)
$(DalamudVersion)
$(DalamudVersion)