Merge branch 'net5' of github.com:goatcorp/Dalamud into net5

This commit is contained in:
goat 2022-08-05 20:01:41 +02:00
commit f9ab1dbf26
No known key found for this signature in database
GPG key ID: 49E2AA8C6A76498B
22 changed files with 1363 additions and 655 deletions

View file

@ -3,7 +3,6 @@ using System.Diagnostics;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -41,11 +40,8 @@ namespace Dalamud
/// <summary>
/// A delegate used from VEH handler on exception which CoreCLR will fast fail by default.
/// </summary>
/// <param name="dumpPath">Path to minidump file created in UTF-16.</param>
/// <param name="logPath">Path to log file to create in UTF-16.</param>
/// <param name="log">Log text in UTF-16.</param>
/// <returns>HGLOBAL for message.</returns>
public delegate IntPtr VehDelegate(IntPtr dumpPath, IntPtr logPath, IntPtr log);
public delegate IntPtr VehDelegate();
/// <summary>
/// Initialize Dalamud.
@ -64,43 +60,19 @@ namespace Dalamud
}
/// <summary>
/// Show error message along with stack trace and exit.
/// Returns stack trace.
/// </summary>
/// <param name="dumpPath">Path to minidump file created in UTF-16.</param>
/// <param name="logPath">Path to log file to create in UTF-16.</param>
/// <param name="log">Log text in UTF-16.</param>
public static IntPtr VehCallback(IntPtr dumpPath, IntPtr logPath, IntPtr log)
/// <returns>HGlobal to wchar_t* stack trace c-string.</returns>
public static IntPtr VehCallback()
{
string stackTrace;
try
{
stackTrace = Environment.StackTrace;
return Marshal.StringToHGlobalUni(Environment.StackTrace);
}
catch (Exception e)
{
stackTrace = "Fail: " + e.ToString();
return Marshal.StringToHGlobalUni("Fail: " + e);
}
var msg = "This may be caused by a faulty plugin, a broken TexTools modification, any other third-party tool or simply a bug in the game.\n\n"
+ "Please attempt an integrity check in the XIVLauncher settings, and disabling plugins you don't need.";
try
{
File.WriteAllText(
Marshal.PtrToStringUni(logPath),
"Stack trace:\n" + stackTrace + "\n\n" + Marshal.PtrToStringUni(log));
}
catch (Exception e)
{
msg += "\n\nAdditionally, failed to write file: " + e.ToString();
}
msg = msg.Format(
Marshal.PtrToStringUni(dumpPath),
Marshal.PtrToStringUni(logPath),
stackTrace);
return Marshal.StringToHGlobalUni(msg);
}
/// <summary>

View file

@ -305,7 +305,7 @@ namespace Dalamud.Game
{
if (this.configuration.AutoUpdatePlugins)
{
PluginManager.PrintUpdatedPlugins(updatedPlugins, Loc.Localize("DalamudPluginAutoUpdate", "Auto-update:"));
Service<PluginManager>.Get().PrintUpdatedPlugins(updatedPlugins, Loc.Localize("DalamudPluginAutoUpdate", "Auto-update:"));
notifications.AddNotification(Loc.Localize("NotificationUpdatedPlugins", "{0} of your plugins were updated.").Format(updatedPlugins.Count), Loc.Localize("NotificationAutoUpdate", "Auto-Update"), NotificationType.Info);
}
else

View file

@ -250,6 +250,11 @@ namespace Dalamud.Interface.Internal
/// </summary>
public void OpenPluginInstaller() => this.pluginWindow.IsOpen = true;
/// <summary>
/// Opens the <see cref="PluginInstallerWindow"/> on the plugin changelogs.
/// </summary>
public void OpenPluginInstallerPluginChangelogs() => this.pluginWindow.OpenPluginChangelogs();
/// <summary>
/// Opens the <see cref="SettingsWindow"/>.
/// </summary>
@ -615,6 +620,16 @@ namespace Dalamud.Interface.Internal
Service<Dalamud>.Get().Unload();
}
if (ImGui.MenuItem("Restart game"))
{
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern void RaiseException(uint dwExceptionCode, uint dwExceptionFlags, uint nNumberOfArguments, IntPtr lpArguments);
RaiseException(0x12345678, 0, 0, IntPtr.Zero);
Process.GetCurrentProcess().Kill();
}
if (ImGui.MenuItem("Kill game"))
{
Process.GetCurrentProcess().Kill();

View file

@ -21,10 +21,7 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
if (plugin.Manifest.Changelog.IsNullOrEmpty())
throw new ArgumentException("Manifest has no changelog.");
var version = plugin.AssemblyName?.Version;
version ??= plugin.Manifest.Testing
? plugin.Manifest.TestingAssemblyVersion
: plugin.Manifest.AssemblyVersion;
var version = plugin.Manifest.EffectiveVersion;
this.Version = version!.ToString();
}

View file

@ -217,6 +217,16 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
this.imageCache.ClearIconCache();
}
/// <summary>
/// Open the window on the plugin changelogs.
/// </summary>
public void OpenPluginChangelogs()
{
this.categoryManager.CurrentGroupIdx = 3;
this.categoryManager.CurrentCategoryIdx = 2;
this.IsOpen = true;
}
private void DrawProgressOverlay()
{
var pluginManager = Service<PluginManager>.Get();
@ -235,16 +245,19 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
ImGui.SetCursorPos(Vector2.Zero);
var windowSize = ImGui.GetWindowSize();
var titleHeight = ImGui.GetFontSize() + (ImGui.GetStyle().FramePadding.Y * 2);
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, Vector2.Zero);
ImGui.PushStyleVar(ImGuiStyleVar.CellPadding, Vector2.Zero);;
ImGui.PushStyleVar(ImGuiStyleVar.ChildBorderSize, 0);
ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, 0);
ImGui.SetNextWindowBgAlpha(0.8f);
if (ImGui.BeginChild("###installerLoadingFrame", new Vector2(-1, -1), false))
{
ImGui.GetWindowDrawList().PushClipRectFullScreen();
ImGui.GetWindowDrawList().AddRectFilled(
ImGui.GetWindowPos() + new Vector2(0, titleHeight),
ImGui.GetWindowPos() + windowSize,
0xCC000000,
ImGui.GetStyle().WindowRounding,
ImDrawFlags.RoundCornersBottom);
ImGui.PopClipRect();
ImGui.SetCursorPosY(windowSize.Y / 2);
switch (this.loadingIndicatorKind)
@ -303,6 +316,7 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
if (currentProgress != total)
{
ImGui.SetCursorPosX(windowSize.X / 3);
ImGui.ProgressBar(currentProgress / (float)total, new Vector2(windowSize.X / 3, 50));
}
}
@ -314,8 +328,6 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
ImGui.EndChild();
}
ImGui.PopStyleVar(5);
}
private void DrawHeader()
@ -325,8 +337,8 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - (5 * ImGuiHelpers.GlobalScale));
var searchInputWidth = 240 * ImGuiHelpers.GlobalScale;
var searchClearButtonWidth = 40 * ImGuiHelpers.GlobalScale;
var searchInputWidth = 180 * ImGuiHelpers.GlobalScale;
var searchClearButtonWidth = 25 * ImGuiHelpers.GlobalScale;
var sortByText = Locs.SortBy_Label;
var sortByTextWidth = ImGui.CalcTextSize(sortByText).X;
@ -349,9 +361,10 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
ImGui.SameLine();
// Shift down a little to align with the middle of the header text
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (headerTextSize.Y / 4) - 2);
var downShift = ImGui.GetCursorPosY() + (headerTextSize.Y / 4) - 2;
ImGui.SetCursorPosY(downShift);
ImGui.SetCursorPosX(windowSize.X - sortSelectWidth - style.ItemSpacing.X - searchInputWidth - searchClearButtonWidth);
ImGui.SetCursorPosX(windowSize.X - sortSelectWidth - (style.ItemSpacing.X * 2) - searchInputWidth - searchClearButtonWidth);
var searchTextChanged = false;
ImGui.SetNextItemWidth(searchInputWidth);
@ -362,6 +375,7 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
100);
ImGui.SameLine();
ImGui.SetCursorPosY(downShift);
ImGui.SetNextItemWidth(searchClearButtonWidth);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Times))
@ -374,7 +388,7 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
this.UpdateCategoriesOnSearchChange();
ImGui.SameLine();
ImGui.SetCursorPosX(windowSize.X - sortSelectWidth);
ImGui.SetCursorPosY(downShift);
ImGui.SetNextItemWidth(selectableWidth);
if (ImGui.BeginCombo(sortByText, this.filterText, ImGuiComboFlags.NoArrowButton))
{
@ -497,7 +511,7 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
if (this.updatePluginCount > 0)
{
PluginManager.PrintUpdatedPlugins(this.updatedPlugins, Locs.PluginUpdateHeader_Chatbox);
Service<PluginManager>.Get().PrintUpdatedPlugins(this.updatedPlugins, Locs.PluginUpdateHeader_Chatbox);
notifications.AddNotification(Locs.Notifications_UpdatesInstalled(this.updatePluginCount), Locs.Notifications_UpdatesInstalledTitle, NotificationType.Success);
var installedGroupIdx = this.categoryManager.GroupList.TakeWhile(
@ -1674,6 +1688,12 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
// Name
var label = plugin.Manifest.Name;
// Dev
if (plugin.IsDev)
{
label += Locs.PluginTitleMod_DevPlugin;
}
// Testing
if (plugin.Manifest.Testing)
{
@ -1841,12 +1861,6 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
ImGui.SameLine();
ImGui.TextColored(ImGuiColors.DalamudGrey3, $" v{plugin.Manifest.EffectiveVersion}");
if (plugin.IsDev)
{
ImGui.SameLine();
ImGui.TextColored(ImGuiColors.DalamudRed, Locs.PluginBody_DeleteDevPlugin);
}
ImGuiHelpers.ScaledDummy(5);
if (this.DrawPluginImages(plugin, manifest, isThirdParty, index))
@ -2557,6 +2571,8 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
public static string PluginTitleMod_TestingVersion => Loc.Localize("InstallerTestingVersion", " (testing version)");
public static string PluginTitleMod_DevPlugin => Loc.Localize("InstallerDevPlugin", " (dev plugin)");
public static string PluginTitleMod_UpdateFailed => Loc.Localize("InstallerUpdateFailed", " (update failed)");
public static string PluginTitleMod_LoadError => Loc.Localize("InstallerLoadError", " (load error)");
@ -2600,9 +2616,6 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
public static string PluginBody_Plugin3rdPartyRepo(string url) => Loc.Localize("InstallerPlugin3rdPartyRepo", "From custom plugin repository {0}").Format(url);
public static string PluginBody_AvailableDevPlugin => Loc.Localize("InstallerDevPlugin", " This plugin is available in one of your repos, please remove it from the devPlugins folder.");
public static string PluginBody_DeleteDevPlugin => Loc.Localize("InstallerDeleteDevPlugin ", " To delete this plugin, please remove it from the devPlugins folder.");
public static string PluginBody_Outdated => Loc.Localize("InstallerOutdatedPluginBody ", "This plugin is outdated and incompatible at the moment. Please wait for it to be updated by its author.");
public static string PluginBody_Orphaned => Loc.Localize("InstallerOrphanedPluginBody ", "This plugin's source repository is no longer available. You may need to reinstall it from its repository, or re-add the repository.");

View file

@ -17,6 +17,8 @@ using Dalamud.Game;
using Dalamud.Game.Gui;
using Dalamud.Game.Gui.Dtr;
using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Interface.Internal;
using Dalamud.Logging.Internal;
using Dalamud.Plugin.Internal.Exceptions;
@ -50,6 +52,8 @@ internal partial class PluginManager : IDisposable, IServiceType
private readonly DirectoryInfo devPluginDirectory;
private readonly BannedPlugin[]? bannedPlugins;
private readonly DalamudLinkPayload openInstallerWindowPluginChangelogsLink;
[ServiceManager.ServiceDependency]
private readonly DalamudConfiguration configuration = Service<DalamudConfiguration>.Get();
@ -101,6 +105,11 @@ internal partial class PluginManager : IDisposable, IServiceType
throw new InvalidDataException("Couldn't deserialize banned plugins manifest.");
}
this.openInstallerWindowPluginChangelogsLink = Service<ChatGui>.Get().AddChatLinkHandler("Dalamud", 1003, (i, m) =>
{
Service<DalamudInterface>.GetNullable()?.OpenPluginInstallerPluginChangelogs();
});
this.ApplyPatches();
}
@ -169,25 +178,38 @@ internal partial class PluginManager : IDisposable, IServiceType
/// </summary>
/// <param name="updateMetadata">The list of updated plugin metadata.</param>
/// <param name="header">The header text to send to chat prior to any update info.</param>
public static void PrintUpdatedPlugins(List<PluginUpdateStatus>? updateMetadata, string header)
public void PrintUpdatedPlugins(List<PluginUpdateStatus>? updateMetadata, string header)
{
var chatGui = Service<ChatGui>.Get();
if (updateMetadata is { Count: > 0 })
{
chatGui.Print(header);
chatGui.PrintChat(new XivChatEntry
{
Message = new SeString(new List<Payload>()
{
new TextPayload(header),
new TextPayload(" ["),
new UIForegroundPayload(500),
this.openInstallerWindowPluginChangelogsLink,
new TextPayload(Loc.Localize("DalamudInstallerPluginChangelogHelp", "Open plugin changelogs") + " "),
RawPayload.LinkTerminator,
new UIForegroundPayload(0),
new TextPayload("]"),
}),
});
foreach (var metadata in updateMetadata)
{
if (metadata.WasUpdated)
{
chatGui.Print(Locs.DalamudPluginUpdateSuccessful(metadata.Name, metadata.Version));
chatGui.Print(Locs.DalamudPluginUpdateSuccessful(metadata.Name, metadata.Version) + (metadata.HasChangelog ? " " : string.Empty));
}
else
{
chatGui.PrintChat(new XivChatEntry
{
Message = Locs.DalamudPluginUpdateFailed(metadata.Name, metadata.Version),
Message = Locs.DalamudPluginUpdateFailed(metadata.Name, metadata.Version) + (metadata.HasChangelog ? " " : string.Empty),
Type = XivChatType.Urgent,
});
}
@ -243,10 +265,12 @@ internal partial class PluginManager : IDisposable, IServiceType
/// <inheritdoc/>
public void Dispose()
{
if (this.InstalledPlugins.Any())
var disposablePlugins =
this.InstalledPlugins.Where(plugin => plugin.State is PluginState.Loaded or PluginState.LoadError).ToArray();
if (disposablePlugins.Any())
{
// Unload them first, just in case some of plugin codes are still running via callbacks initiated externally.
foreach (var plugin in this.InstalledPlugins.Where(plugin => !plugin.Manifest.CanUnloadAsync))
foreach (var plugin in disposablePlugins.Where(plugin => !plugin.Manifest.CanUnloadAsync))
{
try
{
@ -258,7 +282,7 @@ internal partial class PluginManager : IDisposable, IServiceType
}
}
Task.WaitAll(this.InstalledPlugins
Task.WaitAll(disposablePlugins
.Where(plugin => plugin.Manifest.CanUnloadAsync)
.Select(plugin => Task.Run(async () =>
{
@ -278,7 +302,7 @@ internal partial class PluginManager : IDisposable, IServiceType
// Now that we've waited enough, dispose the whole plugin.
// Since plugins should have been unloaded above, this should be done quickly.
foreach (var plugin in this.InstalledPlugins)
foreach (var plugin in disposablePlugins)
plugin.ExplicitDisposeIgnoreExceptions($"Error disposing {plugin.Name}", Log);
}
@ -975,6 +999,7 @@ internal partial class PluginManager : IDisposable, IServiceType
? metadata.UpdateManifest.TestingAssemblyVersion
: metadata.UpdateManifest.AssemblyVersion)!,
WasUpdated = true,
HasChangelog = !metadata.UpdateManifest.Changelog.IsNullOrWhitespace(),
};
if (!dryRun)

View file

@ -138,9 +138,9 @@ internal class LocalDevPlugin : LocalPlugin, IDisposable
return;
}
if (this.State != PluginState.Loaded)
if (this.State != PluginState.Loaded && this.State != PluginState.LoadError)
{
Log.Debug($"Skipping reload of {this.Name}, state ({this.State}) is not {PluginState.Loaded}.");
Log.Debug($"Skipping reload of {this.Name}, state ({this.State}) is not {PluginState.Loaded} nor {PluginState.LoadError}.");
return;
}

View file

@ -26,4 +26,9 @@ internal class PluginUpdateStatus
/// Gets or sets a value indicating whether the plugin was updated.
/// </summary>
public bool WasUpdated { get; set; }
/// <summary>
/// Gets a value indicating whether the plugin has a changelog if it was updated.
/// </summary>
public bool HasChangelog { get; init; }
}