This commit is contained in:
goat 2021-09-27 02:15:11 +02:00
commit c925611674
No known key found for this signature in database
GPG key ID: F18F057873895461
19 changed files with 540 additions and 561 deletions

View file

@ -1,11 +1,14 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Dalamud.Configuration.Internal; using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components; using Dalamud.Interface.Components;
using Dalamud.Interface.Internal.Windows.StyleEditor; using Dalamud.Interface.Internal.Windows.StyleEditor;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using ImGuiNET; using ImGuiNET;
using JetBrains.Annotations; using JetBrains.Annotations;
using Serilog;
namespace Dalamud.Interface.Internal.Windows namespace Dalamud.Interface.Internal.Windows
{ {
@ -14,34 +17,56 @@ namespace Dalamud.Interface.Internal.Windows
private ImGuiColorEditFlags alphaFlags = ImGuiColorEditFlags.None; private ImGuiColorEditFlags alphaFlags = ImGuiColorEditFlags.None;
private StyleModel workStyle = StyleModel.DalamudStandard; private StyleModel workStyle = StyleModel.DalamudStandard;
private int currentSel = 0;
private string initialStyle;
public StyleEditorWindow() public StyleEditorWindow()
: base("Dalamud Style Editor") : base("Dalamud Style Editor")
{ {
IsOpen = true; this.IsOpen = true;
var config = Service<DalamudConfiguration>.Get();
config.SavedStyles ??= new List<StyleModel>();
this.currentSel = config.SavedStyles.FindIndex(x => x.Name == config.ChosenStyle);
this.initialStyle = config.ChosenStyle;
} }
public override void Draw() public override void Draw()
{ {
var config = Service<DalamudConfiguration>.Get(); var config = Service<DalamudConfiguration>.Get();
var style = ImGui.GetStyle(); var style = ImGui.GetStyle();
var a = 0;
ImGui.Text("Choose Style:"); ImGui.Text("Choose Style:");
if (ImGui.Combo("###styleChooserCombo", ref a, new[] { "Dalamud Standard" }, 1)) if (ImGui.Combo("###styleChooserCombo", ref this.currentSel, config.SavedStyles.Select(x => x.Name).ToArray(), 1))
{ {
var newStyle = config.SavedStyles[this.currentSel];
newStyle.Apply();
} }
if (ImGui.Button("Add current style")) if (ImGui.Button("Add new style"))
{ {
var newStyle = StyleModel.DalamudStandard;
newStyle.Name = "New Style";
config.SavedStyles.Add(newStyle);
this.currentSel = config.SavedStyles.Count - 1;
config.Save();
} }
ImGui.SameLine(); ImGui.SameLine();
if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash)) if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash) && this.currentSel != 0)
{ {
this.currentSel--;
var newStyle = config.SavedStyles[this.currentSel];
newStyle.Apply();
config.SavedStyles.RemoveAt(this.currentSel + 1);
config.Save();
} }
if (ImGui.IsItemHovered()) if (ImGui.IsItemHovered())
@ -64,7 +89,23 @@ namespace Dalamud.Interface.Internal.Windows
if (ImGuiComponents.IconButton(FontAwesomeIcon.FileImport)) if (ImGuiComponents.IconButton(FontAwesomeIcon.FileImport))
{ {
var styleJson = ImGui.GetClipboardText();
try
{
var newStyle = StyleModel.FromJsonEncoded(styleJson);
config.SavedStyles.Add(newStyle);
newStyle.Apply();
this.currentSel = config.SavedStyles.Count - 1;
config.Save();
}
catch (Exception ex)
{
Log.Error(ex, "Could not import style");
}
} }
if (ImGui.IsItemHovered()) if (ImGui.IsItemHovered())
@ -74,7 +115,11 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.PushItemWidth(ImGui.GetWindowWidth() * 0.50f); ImGui.PushItemWidth(ImGui.GetWindowWidth() * 0.50f);
if (ImGui.BeginTabBar("StyleEditorTabs")) if (this.currentSel == 0)
{
ImGui.TextColored(ImGuiColors.DalamudRed, "You cannot edit the \"Dalamud Standard\" style. Please add a new style first.");
}
else if (ImGui.BeginTabBar("StyleEditorTabs"))
{ {
if (ImGui.BeginTabItem("Variables")) if (ImGui.BeginTabItem("Variables"))
{ {
@ -178,14 +223,23 @@ namespace Dalamud.Interface.Internal.Windows
if (ImGui.Button("Close")) if (ImGui.Button("Close"))
{ {
var newStyle = config.SavedStyles.FirstOrDefault(x => x.Name == this.initialStyle);
newStyle?.Apply();
this.IsOpen = false;
} }
ImGui.SameLine(); ImGui.SameLine();
if (ImGui.Button("Save and Close")) if (ImGui.Button("Save and Close"))
{ {
config.SavedStyles.Add(); config.ChosenStyle = config.SavedStyles[this.currentSel].Name;
var newStyle = StyleModel.Get();
newStyle.Name = config.ChosenStyle;
config.SavedStyles[this.currentSel] = newStyle;
config.Save();
} }
} }
} }

View file

@ -205,6 +205,11 @@ namespace Dalamud.Configuration.Internal
/// </summary> /// </summary>
public string ChosenStyle { get; set; } = "Dalamud Standard"; public string ChosenStyle { get; set; } = "Dalamud Standard";
/// <summary>
/// Gets or sets a value indicating whether or not Dalamud RMT filtering should be disabled.
/// </summary>
public bool DisableRmtFiltering { get; set; }
/// <summary> /// <summary>
/// Load a configuration from the provided path. /// Load a configuration from the provided path.
/// </summary> /// </summary>

View file

@ -151,13 +151,16 @@ namespace Dalamud.Game
var textVal = message.TextValue; var textVal = message.TextValue;
var matched = this.rmtRegex.IsMatch(textVal); if (!configuration.DisableRmtFiltering)
if (matched)
{ {
// This seems to be a RMT ad - let's not show it var matched = this.rmtRegex.IsMatch(textVal);
Log.Debug("Handled RMT ad: " + message.TextValue); if (matched)
isHandled = true; {
return; // This seems to be a RMT ad - let's not show it
Log.Debug("Handled RMT ad: " + message.TextValue);
isHandled = true;
return;
}
} }
if (configuration.BadWords != null && if (configuration.BadWords != null &&

View file

@ -27,7 +27,7 @@ namespace Dalamud.Game.ClientState.Keys
// The array is accessed in a way that this limit doesn't appear to exist // The array is accessed in a way that this limit doesn't appear to exist
// but there is other state data past this point, and keys beyond here aren't // but there is other state data past this point, and keys beyond here aren't
// generally valid for most things anyway // generally valid for most things anyway
private const int MaxKeyCodeIndex = 0xA0; private const int MaxKeyCode = 0xF0;
private readonly IntPtr bufferBase; private readonly IntPtr bufferBase;
private readonly IntPtr indexBase; private readonly IntPtr indexBase;
private VirtualKey[] validVirtualKeyCache = null; private VirtualKey[] validVirtualKeyCache = null;
@ -104,7 +104,7 @@ namespace Dalamud.Game.ClientState.Keys
/// <param name="vkCode">Virtual key code.</param> /// <param name="vkCode">Virtual key code.</param>
/// <returns>If the code is valid.</returns> /// <returns>If the code is valid.</returns>
public bool IsVirtualKeyValid(int vkCode) public bool IsVirtualKeyValid(int vkCode)
=> vkCode > 0 && vkCode < MaxKeyCodeIndex && this.ConvertVirtualKey(vkCode) != 0; => this.ConvertVirtualKey(vkCode) != 0;
/// <inheritdoc cref="IsVirtualKeyValid(int)"/> /// <inheritdoc cref="IsVirtualKeyValid(int)"/>
public bool IsVirtualKeyValid(VirtualKey vkCode) public bool IsVirtualKeyValid(VirtualKey vkCode)
@ -136,7 +136,7 @@ namespace Dalamud.Game.ClientState.Keys
/// <returns>Converted value.</returns> /// <returns>Converted value.</returns>
private unsafe byte ConvertVirtualKey(int vkCode) private unsafe byte ConvertVirtualKey(int vkCode)
{ {
if (vkCode <= 0 || vkCode >= 240) if (vkCode <= 0 || vkCode >= MaxKeyCode)
return 0; return 0;
return *(byte*)(this.indexBase + vkCode); return *(byte*)(this.indexBase + vkCode);
@ -149,9 +149,6 @@ namespace Dalamud.Game.ClientState.Keys
/// <returns>A reference to the indexed array.</returns> /// <returns>A reference to the indexed array.</returns>
private unsafe ref int GetRefValue(int vkCode) private unsafe ref int GetRefValue(int vkCode)
{ {
if (vkCode < 0 || vkCode > MaxKeyCodeIndex)
throw new ArgumentException($"Keycode state is only valid up to {MaxKeyCodeIndex}");
vkCode = this.ConvertVirtualKey(vkCode); vkCode = this.ConvertVirtualKey(vkCode);
if (vkCode == 0) if (vkCode == 0)

View file

@ -134,6 +134,28 @@ namespace Dalamud.Game
return baseAddress + index; return baseAddress + index;
} }
/// <summary>
/// Try scanning memory for a signature.
/// </summary>
/// <param name="baseAddress">The base address to scan from.</param>
/// <param name="size">The amount of bytes to scan.</param>
/// <param name="signature">The signature to search for.</param>
/// <param name="result">The offset, if found.</param>
/// <returns>true if the signature was found.</returns>
public static bool TryScan(IntPtr baseAddress, int size, string signature, out IntPtr result)
{
try
{
result = Scan(baseAddress, size, signature);
return true;
}
catch (KeyNotFoundException)
{
result = IntPtr.Zero;
return false;
}
}
/// <summary> /// <summary>
/// Scan for a .data address using a .text function. /// Scan for a .data address using a .text function.
/// This is intended to be used with IDA sigs. /// This is intended to be used with IDA sigs.
@ -160,6 +182,29 @@ namespace Dalamud.Game
return IntPtr.Add(instrAddr, Marshal.ReadInt32(instrAddr) + 4); return IntPtr.Add(instrAddr, Marshal.ReadInt32(instrAddr) + 4);
} }
/// <summary>
/// Try scanning for a .data address using a .text function.
/// This is intended to be used with IDA sigs.
/// Place your cursor on the line calling a static address, and create and IDA sig.
/// </summary>
/// <param name="signature">The signature of the function using the data.</param>
/// <param name="result">An IntPtr to the static memory location, if found.</param>
/// <param name="offset">The offset from function start of the instruction using the data.</param>
/// <returns>true if the signature was found.</returns>
public bool TryGetStaticAddressFromSig(string signature, out IntPtr result, int offset = 0)
{
try
{
result = this.GetStaticAddressFromSig(signature, offset);
return true;
}
catch (KeyNotFoundException)
{
result = IntPtr.Zero;
return false;
}
}
/// <summary> /// <summary>
/// Scan for a byte signature in the .data section. /// Scan for a byte signature in the .data section.
/// </summary> /// </summary>
@ -175,6 +220,26 @@ namespace Dalamud.Game
return scanRet; return scanRet;
} }
/// <summary>
/// Try scanning for a byte signature in the .data section.
/// </summary>
/// <param name="signature">The signature.</param>
/// <param name="result">The real offset of the signature, if found.</param>
/// <returns>true if the signature was found.</returns>
public bool TryScanData(string signature, out IntPtr result)
{
try
{
result = this.ScanData(signature);
return true;
}
catch (KeyNotFoundException)
{
result = IntPtr.Zero;
return false;
}
}
/// <summary> /// <summary>
/// Scan for a byte signature in the whole module search area. /// Scan for a byte signature in the whole module search area.
/// </summary> /// </summary>
@ -190,6 +255,26 @@ namespace Dalamud.Game
return scanRet; return scanRet;
} }
/// <summary>
/// Try scanning for a byte signature in the whole module search area.
/// </summary>
/// <param name="signature">The signature.</param>
/// <param name="result">The real offset of the signature, if found.</param>
/// <returns>true if the signature was found.</returns>
public bool TryScanModule(string signature, out IntPtr result)
{
try
{
result = this.ScanModule(signature);
return true;
}
catch (KeyNotFoundException)
{
result = IntPtr.Zero;
return false;
}
}
/// <summary> /// <summary>
/// Resolve a RVA address. /// Resolve a RVA address.
/// </summary> /// </summary>
@ -224,6 +309,26 @@ namespace Dalamud.Game
return scanRet; return scanRet;
} }
/// <summary>
/// Try scanning for a byte signature in the .text section.
/// </summary>
/// <param name="signature">The signature.</param>
/// <param name="result">The real offset of the signature, if found.</param>
/// <returns>true if the signature was found.</returns>
public bool TryScanText(string signature, out IntPtr result)
{
try
{
result = this.ScanText(signature);
return true;
}
catch (KeyNotFoundException)
{
result = IntPtr.Zero;
return false;
}
}
/// <summary> /// <summary>
/// Free the memory of the copied module search area on object disposal, if applicable. /// Free the memory of the copied module search area on object disposal, if applicable.
/// </summary> /// </summary>

View file

@ -340,8 +340,7 @@ namespace Dalamud.Interface.Internal
if (configuration.SavedStyles == null || configuration.SavedStyles.All(x => x.Name != StyleModel.DalamudStandard.Name)) if (configuration.SavedStyles == null || configuration.SavedStyles.All(x => x.Name != StyleModel.DalamudStandard.Name))
{ {
configuration.SavedStyles = new List<StyleModel>(); configuration.SavedStyles = new List<StyleModel> { StyleModel.DalamudStandard };
configuration.SavedStyles.Add(StyleModel.DalamudStandard);
configuration.ChosenStyle = StyleModel.DalamudStandard.Name; configuration.ChosenStyle = StyleModel.DalamudStandard.Name;
} }

View file

@ -25,7 +25,6 @@ using Dalamud.Plugin.Internal.Types;
using Dalamud.Utility; using Dalamud.Utility;
using ImGuiNET; using ImGuiNET;
using ImGuiScene; using ImGuiScene;
using Microsoft.VisualBasic;
namespace Dalamud.Interface.Internal.Windows namespace Dalamud.Interface.Internal.Windows
{ {
@ -56,7 +55,7 @@ namespace Dalamud.Interface.Internal.Windows
private string[] testerImagePaths = new string[5]; private string[] testerImagePaths = new string[5];
private string testerIconPath = string.Empty; private string testerIconPath = string.Empty;
private TextureWrap?[]? testerImages; private TextureWrap?[] testerImages;
private TextureWrap? testerIcon; private TextureWrap? testerIcon;
private bool testerError = false; private bool testerError = false;
@ -76,9 +75,8 @@ namespace Dalamud.Interface.Internal.Windows
private List<AvailablePluginUpdate> pluginListUpdatable = new(); private List<AvailablePluginUpdate> pluginListUpdatable = new();
private bool hasDevPlugins = false; private bool hasDevPlugins = false;
private bool downloadingIcons = false; private Dictionary<string, TextureWrap?> pluginIconMap = new();
private Dictionary<string, (bool IsDownloaded, TextureWrap?[]? Textures)> pluginImagesMap = new(); private Dictionary<string, TextureWrap?[]> pluginImagesMap = new();
private Dictionary<string, (bool IsDownloaded, TextureWrap? Texture)> pluginIconMap = new();
private string searchText = string.Empty; private string searchText = string.Empty;
@ -197,8 +195,6 @@ namespace Dalamud.Interface.Internal.Windows
{ {
this.pluginIconMap.Clear(); this.pluginIconMap.Clear();
this.pluginImagesMap.Clear(); this.pluginImagesMap.Clear();
this.DownloadPluginIcons();
} }
private static string? GetPluginIconUrl(PluginManifest manifest, bool isThirdParty, bool isTesting) private static string? GetPluginIconUrl(PluginManifest manifest, bool isThirdParty, bool isTesting)
@ -209,10 +205,18 @@ namespace Dalamud.Interface.Internal.Windows
return MainRepoImageUrl.Format(isTesting ? "testing" : "plugins", manifest.InternalName, "icon.png"); return MainRepoImageUrl.Format(isTesting ? "testing" : "plugins", manifest.InternalName, "icon.png");
} }
private static List<string>? GetPluginImageUrls(PluginManifest manifest, bool isThirdParty, bool isTesting) private static List<string?> GetPluginImageUrls(PluginManifest manifest, bool isThirdParty, bool isTesting)
{ {
if (isThirdParty) if (isThirdParty)
{
if (manifest.ImageUrls.Count > 5)
{
Log.Warning($"Plugin {manifest.InternalName} has too many images");
return manifest.ImageUrls.Take(5).ToList();
}
return manifest.ImageUrls; return manifest.ImageUrls;
}
var output = new List<string>(); var output = new List<string>();
for (var i = 1; i <= 5; i++) for (var i = 1; i <= 5; i++)
@ -223,6 +227,36 @@ namespace Dalamud.Interface.Internal.Windows
return output; return output;
} }
private static FileInfo? GetPluginIconFileInfo(LocalPlugin? plugin)
{
var pluginDir = plugin.DllFile.Directory;
var devUrl = new FileInfo(Path.Combine(pluginDir.FullName, "images", "icon.png"));
if (devUrl.Exists)
return devUrl;
return null;
}
private static List<FileInfo?> GetPluginImageFileInfos(LocalPlugin? plugin)
{
var pluginDir = plugin.DllFile.Directory;
var output = new List<FileInfo>();
for (var i = 1; i <= 5; i++)
{
var devUrl = new FileInfo(Path.Combine(pluginDir.FullName, "images", $"image{i}.png"));
if (devUrl.Exists)
{
output.Add(devUrl);
continue;
}
output.Add(null);
}
return output;
}
private void DrawHeader() private void DrawHeader()
{ {
var style = ImGui.GetStyle(); var style = ImGui.GetStyle();
@ -555,7 +589,6 @@ namespace Dalamud.Interface.Internal.Windows
} }
} }
// TODO: Technically, we really should just load images from a devplugin folder
private void DrawImageTester() private void DrawImageTester()
{ {
var sectionSize = ImGuiHelpers.GlobalScale * 66; var sectionSize = ImGuiHelpers.GlobalScale * 66;
@ -800,7 +833,7 @@ namespace Dalamud.Interface.Internal.Windows
return ready; return ready;
} }
private bool DrawPluginCollapsingHeader(string label, PluginManifest manifest, bool trouble, bool updateAvailable, bool isNew, Action drawContextMenuAction, int index) private bool DrawPluginCollapsingHeader(string label, LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty, bool trouble, bool updateAvailable, bool isNew, Action drawContextMenuAction, int index)
{ {
ImGui.Separator(); ImGui.Separator();
@ -837,12 +870,20 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.SetCursorPos(startCursor); ImGui.SetCursorPos(startCursor);
var hasIcon = this.pluginIconMap.TryGetValue(manifest.InternalName, out var icon);
var iconTex = this.defaultIcon; var iconTex = this.defaultIcon;
if (hasIcon && icon.IsDownloaded && icon.Texture != null) var hasIcon = this.pluginIconMap.TryGetValue(manifest.InternalName, out var cachedIconTex);
if (!hasIcon)
{ {
iconTex = icon.Texture; this.pluginIconMap.Add(manifest.InternalName, null);
Task.Run(async () => await this.DownloadPluginIconAsync(plugin, manifest, isThirdParty));
}
else if (cachedIconTex != null)
{
iconTex = cachedIconTex;
}
else
{
// nothing
} }
var iconSize = ImGuiHelpers.ScaledVector2(64, 64); var iconSize = ImGuiHelpers.ScaledVector2(64, 64);
@ -868,13 +909,14 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.SameLine(); ImGui.SameLine();
var cursor = ImGui.GetCursorPos(); var cursor = ImGui.GetCursorPos();
// Name // Name
ImGui.Text(label); ImGui.Text(label);
// Download count // Download count
var downloadCountText = manifest.DownloadCount > 0 var downloadCountText = manifest.DownloadCount > 0
? Locs.PluginBody_AuthorWithDownloadCount(manifest.Author, manifest.DownloadCount) ? Locs.PluginBody_AuthorWithDownloadCount(manifest.Author, manifest.DownloadCount)
: Locs.PluginBody_AuthorWithDownloadCountUnavailable(manifest.Author); : Locs.PluginBody_AuthorWithDownloadCountUnavailable(manifest.Author);
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextColored(ImGuiColors.DalamudGrey3, downloadCountText); ImGui.TextColored(ImGuiColors.DalamudGrey3, downloadCountText);
@ -927,7 +969,8 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.PushID($"available{index}{manifest.InternalName}"); ImGui.PushID($"available{index}{manifest.InternalName}");
if (this.DrawPluginCollapsingHeader(label, manifest, false, false, !wasSeen, () => this.DrawAvailablePluginContextMenu(manifest), index)) var isThirdParty = manifest.SourceRepo.IsThirdParty;
if (this.DrawPluginCollapsingHeader(label, null, manifest, isThirdParty, false, false, !wasSeen, () => this.DrawAvailablePluginContextMenu(manifest), index))
{ {
if (!wasSeen) if (!wasSeen)
configuration.SeenPluginInternalName.Add(manifest.InternalName); configuration.SeenPluginInternalName.Add(manifest.InternalName);
@ -996,7 +1039,7 @@ namespace Dalamud.Interface.Internal.Windows
ImGuiHelpers.ScaledDummy(5); ImGuiHelpers.ScaledDummy(5);
if (this.DrawPluginImages(manifest, index, manifest.SourceRepo.IsThirdParty)) if (this.DrawPluginImages(null, manifest, isThirdParty, index))
ImGuiHelpers.ScaledDummy(5); ImGuiHelpers.ScaledDummy(5);
ImGui.Unindent(); ImGui.Unindent();
@ -1124,15 +1167,22 @@ namespace Dalamud.Interface.Internal.Windows
} }
// Outdated API level // Outdated API level
if (plugin.Manifest.DalamudApiLevel < PluginManager.DalamudApiLevel) if (plugin.IsOutdated)
{ {
label += Locs.PluginTitleMod_OutdatedError; label += Locs.PluginTitleMod_OutdatedError;
trouble = true; trouble = true;
} }
// Banned
if (plugin.IsBanned)
{
label += Locs.PluginTitleMod_BannedError;
trouble = true;
}
ImGui.PushID($"installed{index}{plugin.Manifest.InternalName}"); ImGui.PushID($"installed{index}{plugin.Manifest.InternalName}");
if (this.DrawPluginCollapsingHeader(label, plugin.Manifest, trouble, availablePluginUpdate != default, false, () => this.DrawInstalledPluginContextMenu(plugin), index)) if (this.DrawPluginCollapsingHeader(label, plugin, plugin.Manifest, plugin.Manifest.IsThirdParty, trouble, availablePluginUpdate != default, false, () => this.DrawInstalledPluginContextMenu(plugin), index))
{ {
if (!this.WasPluginSeen(plugin.Manifest.InternalName)) if (!this.WasPluginSeen(plugin.Manifest.InternalName))
configuration.SeenPluginInternalName.Add(plugin.Manifest.InternalName); configuration.SeenPluginInternalName.Add(plugin.Manifest.InternalName);
@ -1154,7 +1204,7 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextColored(ImGuiColors.DalamudGrey3, downloadText); ImGui.TextColored(ImGuiColors.DalamudGrey3, downloadText);
var isThirdParty = !string.IsNullOrEmpty(manifest.InstalledFromUrl); var isThirdParty = manifest.IsThirdParty;
// Installed from // Installed from
if (plugin.IsDev) if (plugin.IsDev)
@ -1174,13 +1224,20 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.TextWrapped(manifest.Description); ImGui.TextWrapped(manifest.Description);
} }
if (plugin.Manifest.DalamudApiLevel < PluginManager.DalamudApiLevel) if (plugin.IsOutdated)
{ {
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed); ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
ImGui.TextWrapped(Locs.PluginBody_Outdated); ImGui.TextWrapped(Locs.PluginBody_Outdated);
ImGui.PopStyleColor(); ImGui.PopStyleColor();
} }
if (plugin.IsBanned)
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
ImGui.TextWrapped(Locs.PluginBody_Banned);
ImGui.PopStyleColor();
}
// Available commands (if loaded) // Available commands (if loaded)
if (plugin.IsLoaded) if (plugin.IsLoaded)
{ {
@ -1201,6 +1258,7 @@ namespace Dalamud.Interface.Internal.Windows
// Controls // Controls
this.DrawPluginControlButton(plugin); this.DrawPluginControlButton(plugin);
this.DrawDevPluginButtons(plugin); this.DrawDevPluginButtons(plugin);
this.DrawDeletePluginButton(plugin);
this.DrawVisitRepoUrlButton(plugin.Manifest.RepoUrl); this.DrawVisitRepoUrlButton(plugin.Manifest.RepoUrl);
if (availablePluginUpdate != default) if (availablePluginUpdate != default)
@ -1217,9 +1275,8 @@ namespace Dalamud.Interface.Internal.Windows
ImGuiHelpers.ScaledDummy(5); ImGuiHelpers.ScaledDummy(5);
this.DrawPluginImages(manifest, index, isThirdParty); if (this.DrawPluginImages(plugin, manifest, isThirdParty, index))
ImGuiHelpers.ScaledDummy(5);
ImGuiHelpers.ScaledDummy(5);
ImGui.Unindent(); ImGui.Unindent();
} }
@ -1263,7 +1320,7 @@ namespace Dalamud.Interface.Internal.Windows
var disabled = this.updateStatus == OperationStatus.InProgress || this.installStatus == OperationStatus.InProgress; var disabled = this.updateStatus == OperationStatus.InProgress || this.installStatus == OperationStatus.InProgress;
// Disable everything if the plugin is outdated // Disable everything if the plugin is outdated
disabled = disabled || (plugin.Manifest.DalamudApiLevel < PluginManager.DalamudApiLevel && !configuration.LoadAllApiLevels); disabled = disabled || (plugin.IsOutdated && !configuration.LoadAllApiLevels) || plugin.IsBanned;
if (plugin.State == PluginState.InProgress) if (plugin.State == PluginState.InProgress)
{ {
@ -1411,7 +1468,6 @@ namespace Dalamud.Interface.Internal.Windows
private void DrawDevPluginButtons(LocalPlugin localPlugin) private void DrawDevPluginButtons(LocalPlugin localPlugin)
{ {
var configuration = Service<DalamudConfiguration>.Get(); var configuration = Service<DalamudConfiguration>.Get();
var pluginManager = Service<PluginManager>.Get();
if (localPlugin is LocalDevPlugin plugin) if (localPlugin is LocalDevPlugin plugin)
{ {
@ -1454,33 +1510,40 @@ namespace Dalamud.Interface.Internal.Windows
{ {
ImGui.SetTooltip(Locs.PluginButtonToolTip_AutomaticReloading); ImGui.SetTooltip(Locs.PluginButtonToolTip_AutomaticReloading);
} }
}
}
// Delete private void DrawDeletePluginButton(LocalPlugin plugin)
if (plugin.State == PluginState.Unloaded) {
var unloaded = plugin.State == PluginState.Unloaded;
var showButton = unloaded && (plugin.IsDev || plugin.IsOutdated || plugin.IsBanned);
if (!showButton)
return;
var pluginManager = Service<PluginManager>.Get();
ImGui.SameLine();
if (ImGuiComponents.IconButton(FontAwesomeIcon.TrashAlt))
{
try
{ {
ImGui.SameLine(); plugin.DllFile.Delete();
if (ImGuiComponents.IconButton(FontAwesomeIcon.TrashAlt)) pluginManager.RemovePlugin(plugin);
{
try
{
plugin.DllFile.Delete();
pluginManager.RemovePlugin(plugin);
}
catch (Exception ex)
{
Log.Error(ex, $"Plugin installer threw an error during removal of {plugin.Name}");
this.errorModalMessage = Locs.ErrorModal_DeleteFail(plugin.Name);
this.errorModalDrawing = true;
this.errorModalOnNextFrame = true;
}
}
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip(Locs.PluginBody_DeleteDevPlugin);
}
} }
catch (Exception ex)
{
Log.Error(ex, $"Plugin installer threw an error during removal of {plugin.Name}");
this.errorModalMessage = Locs.ErrorModal_DeleteFail(plugin.Name);
this.errorModalDrawing = true;
this.errorModalOnNextFrame = true;
}
}
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip(Locs.PluginButtonToolTip_DeletePlugin);
} }
} }
@ -1510,18 +1573,18 @@ namespace Dalamud.Interface.Internal.Windows
} }
} }
private bool DrawPluginImages(PluginManifest manifest, int index, bool isThirdParty) private bool DrawPluginImages(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty, int index)
{ {
if (!this.pluginImagesMap.TryGetValue(manifest.InternalName, out var images)) var hasImages = this.pluginImagesMap.TryGetValue(manifest.InternalName, out var imageTextures);
if (!hasImages)
{ {
Task.Run(() => this.DownloadPluginImagesAsync(manifest, isThirdParty)); this.pluginImagesMap.Add(manifest.InternalName, Array.Empty<TextureWrap>());
Task.Run(async () => await this.DownloadPluginImagesAsync(plugin, manifest, isThirdParty));
return false; return false;
} }
if (!images.IsDownloaded) if (imageTextures.Length == 0)
return false;
if (images.Textures == null)
return false; return false;
const float thumbFactor = 2.7f; const float thumbFactor = 2.7f;
@ -1534,42 +1597,39 @@ namespace Dalamud.Interface.Internal.Windows
if (ImGui.BeginChild($"plugin{index}ImageScrolling", new Vector2(width - (70 * ImGuiHelpers.GlobalScale), (PluginImageHeight / thumbFactor) + scrollBarSize), false, ImGuiWindowFlags.HorizontalScrollbar | ImGuiWindowFlags.NoScrollWithMouse | ImGuiWindowFlags.NoBackground)) if (ImGui.BeginChild($"plugin{index}ImageScrolling", new Vector2(width - (70 * ImGuiHelpers.GlobalScale), (PluginImageHeight / thumbFactor) + scrollBarSize), false, ImGuiWindowFlags.HorizontalScrollbar | ImGuiWindowFlags.NoScrollWithMouse | ImGuiWindowFlags.NoBackground))
{ {
if (images.Textures != null && images.Textures is { Length: > 0 }) for (var i = 0; i < imageTextures.Length; i++)
{ {
for (var i = 0; i < images.Textures.Length; i++) var image = imageTextures[i];
if (image == null)
continue;
ImGui.PushStyleVar(ImGuiStyleVar.PopupBorderSize, 0);
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, Vector2.Zero);
var popupId = $"plugin{index}image{i}";
if (ImGui.BeginPopup(popupId))
{ {
var popupId = $"plugin{index}image{i}"; if (ImGui.ImageButton(image.ImGuiHandle, new Vector2(image.Width, image.Height)))
var image = images.Textures[i]; ImGui.CloseCurrentPopup();
if (image == null)
continue;
ImGui.PushStyleVar(ImGuiStyleVar.PopupBorderSize, 0); ImGui.EndPopup();
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero); }
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, Vector2.Zero);
if (ImGui.BeginPopup(popupId)) ImGui.PopStyleVar(3);
{
if (ImGui.ImageButton(image.ImGuiHandle, new Vector2(image.Width, image.Height)))
ImGui.CloseCurrentPopup();
ImGui.EndPopup(); ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, Vector2.Zero);
}
ImGui.PopStyleVar(3); if (ImGui.ImageButton(image.ImGuiHandle, ImGuiHelpers.ScaledVector2(image.Width / thumbFactor, image.Height / thumbFactor)))
ImGui.OpenPopup(popupId);
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, Vector2.Zero); ImGui.PopStyleVar();
if (ImGui.ImageButton(image.ImGuiHandle, ImGuiHelpers.ScaledVector2(image.Width / thumbFactor, image.Height / thumbFactor))) if (i < imageTextures.Length - 1)
ImGui.OpenPopup(popupId); {
ImGui.SameLine();
ImGui.PopStyleVar(); ImGuiHelpers.ScaledDummy(5);
ImGui.SameLine();
if (i < images.Textures.Length - 1)
{
ImGui.SameLine();
ImGuiHelpers.ScaledDummy(5);
ImGui.SameLine();
}
} }
} }
} }
@ -1612,8 +1672,6 @@ namespace Dalamud.Interface.Internal.Windows
.ToList(); .ToList();
this.pluginListUpdatable = pluginManager.UpdatablePlugins.ToList(); this.pluginListUpdatable = pluginManager.UpdatablePlugins.ToList();
this.ResortPlugins(); this.ResortPlugins();
this.DownloadPluginIcons();
} }
private void OnInstalledPluginsChanged() private void OnInstalledPluginsChanged()
@ -1624,8 +1682,6 @@ namespace Dalamud.Interface.Internal.Windows
this.pluginListUpdatable = pluginManager.UpdatablePlugins.ToList(); this.pluginListUpdatable = pluginManager.UpdatablePlugins.ToList();
this.hasDevPlugins = this.pluginListInstalled.Any(plugin => plugin.IsDev); this.hasDevPlugins = this.pluginListInstalled.Any(plugin => plugin.IsDev);
this.ResortPlugins(); this.ResortPlugins();
this.DownloadPluginIcons();
} }
private void ResortPlugins() private void ResortPlugins()
@ -1705,133 +1761,173 @@ namespace Dalamud.Interface.Internal.Windows
this.errorModalOnNextFrame = true; this.errorModalOnNextFrame = true;
} }
private void DownloadPluginIcons() private async Task DownloadPluginIconAsync(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty)
{ {
if (this.downloadingIcons) var interfaceManager = Service<InterfaceManager>.Get();
var pluginManager = Service<PluginManager>.Get();
static bool ValidateIcon(TextureWrap icon, string loc)
{ {
Log.Error("Already downloading icons, skipping..."); if (icon == null)
return false;
if (icon.Height > PluginIconHeight || icon.Width > PluginIconWidth)
{
Log.Error($"Icon at {loc} was not of the correct resolution.");
return false;
}
if (icon.Height != icon.Width)
{
Log.Error($"Icon at {loc} was not square.");
return false;
}
return true;
}
if (plugin != null && plugin.IsDev)
{
var file = GetPluginIconFileInfo(plugin);
if (file != null)
{
Log.Verbose($"Fetching icon for {manifest.InternalName} from {file.FullName}");
var icon = interfaceManager.LoadImage(file.FullName);
if (!ValidateIcon(icon, file.FullName))
return;
this.pluginIconMap[manifest.InternalName] = icon;
Log.Verbose($"Plugin icon for {manifest.InternalName} loaded from disk");
}
return; return;
} }
this.downloadingIcons = true; var useTesting = pluginManager.UseTesting(manifest);
var url = GetPluginIconUrl(manifest, isThirdParty, useTesting);
var pluginManager = Service<PluginManager>.Get();
Log.Verbose("Start downloading plugin icons...");
Task.Run(async () =>
{
var plugins = pluginManager.AvailablePlugins.Select(x => x);
foreach (var pluginManifest in plugins)
{
var useTesting = pluginManager.UseTesting(pluginManifest);
if (!this.pluginIconMap.ContainsKey(pluginManifest.InternalName))
await this.DownloadPluginIconAsync(pluginManifest, useTesting);
}
}).ContinueWith(t =>
{
Log.Verbose($"Icon download finished, faulted: {t.IsFaulted}");
this.downloadingIcons = false;
});
}
private async Task DownloadPluginIconAsync(RemotePluginManifest manifest, bool isTesting)
{
var interfaceManager = Service<InterfaceManager>.Get();
Log.Verbose($"Downloading icon for {manifest.InternalName}");
this.pluginIconMap.Add(manifest.InternalName, (false, null));
var url = GetPluginIconUrl(manifest, manifest.SourceRepo.IsThirdParty, isTesting);
Log.Verbose($"Icon from {url}");
if (url != null) if (url != null)
{ {
Log.Verbose($"Downloading icon for {manifest.InternalName} from {url}");
var data = await this.httpClient.GetAsync(url); var data = await this.httpClient.GetAsync(url);
if (data.StatusCode == HttpStatusCode.NotFound) if (data.StatusCode == HttpStatusCode.NotFound)
return; return;
data.EnsureSuccessStatusCode(); data.EnsureSuccessStatusCode();
var icon = interfaceManager.LoadImage(await data.Content.ReadAsByteArrayAsync()); var icon = interfaceManager.LoadImage(await data.Content.ReadAsByteArrayAsync());
if (icon != null) if (!ValidateIcon(icon, url))
{ return;
if (icon.Height > PluginIconHeight || icon.Width > PluginIconWidth)
{
Log.Error($"Icon at {manifest.IconUrl} was not of the correct resolution.");
return;
}
if (icon.Height != icon.Width) this.pluginIconMap[manifest.InternalName] = icon;
{ Log.Verbose($"Plugin icon for {manifest.InternalName} downloaded");
Log.Error($"Icon at {manifest.IconUrl} was not square.");
return;
}
this.pluginIconMap[manifest.InternalName] = (true, icon); return;
}
} }
Log.Verbose($"Icon for {manifest.InternalName} is not available");
} }
private async Task DownloadPluginImagesAsync(PluginManifest manifest, bool isThirdParty) private async Task DownloadPluginImagesAsync(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty)
{ {
var interfaceManager = Service<InterfaceManager>.Get(); var interfaceManager = Service<InterfaceManager>.Get();
var pluginManager = Service<PluginManager>.Get(); var pluginManager = Service<PluginManager>.Get();
Log.Verbose($"Downloading images for {manifest.InternalName}"); static bool ValidateImage(TextureWrap image, string loc)
this.pluginImagesMap.Add(manifest.InternalName, (false, null));
var urls = GetPluginImageUrls(manifest, isThirdParty, pluginManager.UseTesting(manifest));
var didAny = false;
if (urls != null)
{ {
if (urls.Count > 5) if (image == null)
return false;
if (image.Height != PluginImageHeight || image.Width != PluginImageWidth)
{ {
Log.Error($"Plugin {manifest.InternalName} has too many images."); Log.Error($"Image at {loc} was not of the correct resolution.");
return; return false;
} }
return true;
}
if (plugin != null && plugin.IsDev)
{
var files = GetPluginImageFileInfos(plugin);
if (files != null)
{
var didAny = false;
var pluginImages = new TextureWrap[files.Count];
for (var i = 0; i < files.Count; i++)
{
var file = files[i];
if (file == null)
continue;
Log.Verbose($"Loading image{i + 1} for {manifest.InternalName} from {file.FullName}");
var image = interfaceManager.LoadImage(await File.ReadAllBytesAsync(file.FullName));
if (!ValidateImage(image, file.FullName))
continue;
Log.Verbose($"Plugin image{i + 1} for {manifest.InternalName} loaded from disk");
pluginImages[i] = image;
didAny = true;
}
if (didAny)
{
Log.Verbose($"Plugin images for {manifest.InternalName} loaded from disk");
this.pluginImagesMap[manifest.InternalName] = pluginImages;
return;
}
}
// Dev plugins are loaded from disk only
return;
}
var useTesting = pluginManager.UseTesting(manifest);
var urls = GetPluginImageUrls(manifest, isThirdParty, useTesting);
if (urls != null)
{
var didAny = false;
var pluginImages = new TextureWrap[urls.Count]; var pluginImages = new TextureWrap[urls.Count];
for (var i = 0; i < urls.Count; i++) for (var i = 0; i < urls.Count; i++)
{ {
var data = await this.httpClient.GetAsync(urls[i]); var url = urls[i];
Serilog.Log.Information($"Download from {urls[i]}"); Log.Verbose($"Downloading image{i + 1} for {manifest.InternalName} from {url}");
var data = await this.httpClient.GetAsync(url);
if (data.StatusCode == HttpStatusCode.NotFound) if (data.StatusCode == HttpStatusCode.NotFound)
continue; continue;
data.EnsureSuccessStatusCode(); data.EnsureSuccessStatusCode();
var image = interfaceManager.LoadImage(await data.Content.ReadAsByteArrayAsync()); var image = interfaceManager.LoadImage(await data.Content.ReadAsByteArrayAsync());
if (image == null) if (!ValidateImage(image, url))
{ continue;
return;
}
if (image.Height != PluginImageHeight || image.Width != PluginImageWidth)
{
Log.Error($"Image at {urls[i]} was not of the correct resolution.");
return;
}
didAny = true;
Log.Verbose($"Plugin image{i + 1} for {manifest.InternalName} downloaded");
pluginImages[i] = image; pluginImages[i] = image;
didAny = true;
} }
if (didAny) if (didAny)
{ {
this.pluginImagesMap[manifest.InternalName] = (true, pluginImages); Log.Verbose($"Plugin images for {manifest.InternalName} downloaded");
this.pluginImagesMap[manifest.InternalName] = pluginImages;
return;
} }
} }
Log.Verbose($"Plugin images for {manifest.InternalName} downloaded"); Log.Verbose($"Images for {manifest.InternalName} are not available");
} }
[SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "Disregard here")] [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "Disregard here")]
@ -1919,6 +2015,8 @@ namespace Dalamud.Interface.Internal.Windows
public static string PluginTitleMod_OutdatedError => Loc.Localize("InstallerOutdatedError", " (outdated)"); public static string PluginTitleMod_OutdatedError => Loc.Localize("InstallerOutdatedError", " (outdated)");
public static string PluginTitleMod_BannedError => Loc.Localize("InstallerOutdatedError", " (banned)");
public static string PluginTitleMod_New => Loc.Localize("InstallerNewPlugin ", " New!"); public static string PluginTitleMod_New => Loc.Localize("InstallerNewPlugin ", " New!");
#endregion #endregion
@ -1953,6 +2051,8 @@ namespace Dalamud.Interface.Internal.Windows
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_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_Banned => Loc.Localize("InstallerBannedPluginBody ", "This plugin version is banned and not available at the moment. Please wait for it to be updated by its author.");
#endregion #endregion
#region Plugin buttons #region Plugin buttons

View file

@ -59,6 +59,7 @@ namespace Dalamud.Interface.Internal.Windows
private bool printPluginsWelcomeMsg; private bool printPluginsWelcomeMsg;
private bool autoUpdatePlugins; private bool autoUpdatePlugins;
private bool doButtonsSystemMenu; private bool doButtonsSystemMenu;
private bool disableRmtFiltering;
#region Experimental #region Experimental
@ -99,6 +100,7 @@ namespace Dalamud.Interface.Internal.Windows
this.printPluginsWelcomeMsg = configuration.PrintPluginsWelcomeMsg; this.printPluginsWelcomeMsg = configuration.PrintPluginsWelcomeMsg;
this.autoUpdatePlugins = configuration.AutoUpdatePlugins; this.autoUpdatePlugins = configuration.AutoUpdatePlugins;
this.doButtonsSystemMenu = configuration.DoButtonsSystemMenu; this.doButtonsSystemMenu = configuration.DoButtonsSystemMenu;
this.disableRmtFiltering = configuration.DisableRmtFiltering;
this.languages = Localization.ApplicableLangCodes.Prepend("en").ToArray(); this.languages = Localization.ApplicableLangCodes.Prepend("en").ToArray();
try try
@ -238,6 +240,9 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.Checkbox(Loc.Localize("DalamudSettingsSystemMenu", "Dalamud buttons in system menu"), ref this.doButtonsSystemMenu); ImGui.Checkbox(Loc.Localize("DalamudSettingsSystemMenu", "Dalamud buttons in system menu"), ref this.doButtonsSystemMenu);
ImGui.TextColored(this.hintTextColor, Loc.Localize("DalamudSettingsSystemMenuMsgHint", "Add buttons for Dalamud plugins and settings to the system menu.")); ImGui.TextColored(this.hintTextColor, Loc.Localize("DalamudSettingsSystemMenuMsgHint", "Add buttons for Dalamud plugins and settings to the system menu."));
ImGui.Checkbox(Loc.Localize("DalamudSettingsDisableRmtFiltering", "Disable RMT Filtering"), ref this.disableRmtFiltering);
ImGui.TextColored(this.hintTextColor, Loc.Localize("DalamudSettingsDisableRmtFilteringMsgHint", "Disable dalamud's built-in RMT ad filtering."));
} }
private void DrawLookAndFeelTab() private void DrawLookAndFeelTab()
@ -689,6 +694,7 @@ namespace Dalamud.Interface.Internal.Windows
configuration.PrintPluginsWelcomeMsg = this.printPluginsWelcomeMsg; configuration.PrintPluginsWelcomeMsg = this.printPluginsWelcomeMsg;
configuration.AutoUpdatePlugins = this.autoUpdatePlugins; configuration.AutoUpdatePlugins = this.autoUpdatePlugins;
configuration.DoButtonsSystemMenu = this.doButtonsSystemMenu; configuration.DoButtonsSystemMenu = this.doButtonsSystemMenu;
configuration.DisableRmtFiltering = this.disableRmtFiltering;
configuration.Save(); configuration.Save();

View file

@ -0,0 +1,22 @@
namespace Dalamud.Plugin.Internal.Exceptions
{
/// <summary>
/// This represents a banned plugin that attempted an operation.
/// </summary>
internal class BannedPluginException : PluginException
{
/// <summary>
/// Initializes a new instance of the <see cref="BannedPluginException"/> class.
/// </summary>
/// <param name="message">The message describing the invalid operation.</param>
public BannedPluginException(string message)
{
this.Message = message;
}
/// <summary>
/// Gets the message describing the invalid operation.
/// </summary>
public override string Message { get; }
}
}

View file

@ -145,19 +145,17 @@ namespace Dalamud.Plugin.Internal
return; return;
} }
var notificationManager = Service<NotificationManager>.Get();
try try
{ {
this.Reload(); this.Reload();
Service<NotificationManager>.Get() notificationManager.AddNotification($"The DevPlugin '{this.Name} was reloaded successfully.", "Plugin reloaded!", NotificationType.Success);
.AddNotification(
$"The DevPlugin '{this.Name} was reloaded successfully.", "Plugin reloaded!", NotificationType.Success);
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex, "DevPlugin reload failed."); Log.Error(ex, "DevPlugin reload failed.");
Service<NotificationManager>.Get() notificationManager.AddNotification($"The DevPlugin '{this.Name} could not be reloaded.", "Plugin reload failed!", NotificationType.Error);
.AddNotification(
$"The DevPlugin '{this.Name} could not be reloaded.", "Plugin reload failed!", NotificationType.Error);
} }
}, },
this.fileWatcherTokenSource.Token); this.fileWatcherTokenSource.Token);

View file

@ -86,10 +86,8 @@ namespace Dalamud.Plugin.Internal
var assemblyVersion = this.pluginAssembly.GetName().Version; var assemblyVersion = this.pluginAssembly.GetName().Version;
// Files that may or may not exist // Although it is conditionally used here, we need to set the initial value regardless.
this.manifestFile = LocalPluginManifest.GetManifestFile(this.DllFile); this.manifestFile = LocalPluginManifest.GetManifestFile(this.DllFile);
this.disabledFile = LocalPluginManifest.GetDisabledFile(this.DllFile);
this.testingFile = LocalPluginManifest.GetTestingFile(this.DllFile);
// If the parameter manifest was null // If the parameter manifest was null
if (manifest == null) if (manifest == null)
@ -108,28 +106,32 @@ namespace Dalamud.Plugin.Internal
// Save the manifest to disk so there won't be any problems later. // Save the manifest to disk so there won't be any problems later.
// We'll update the name property after it can be retrieved from the instance. // We'll update the name property after it can be retrieved from the instance.
var manifestFile = LocalPluginManifest.GetManifestFile(this.DllFile); this.Manifest.Save(this.manifestFile);
this.Manifest.Save(manifestFile);
} }
else else
{ {
this.Manifest = manifest; this.Manifest = manifest;
} }
// This bit converts from ".disabled" functionality to using the manifest. // This converts from the ".disabled" file feature to the manifest instead.
this.disabledFile = LocalPluginManifest.GetDisabledFile(this.DllFile);
if (this.disabledFile.Exists) if (this.disabledFile.Exists)
{ {
this.Manifest.Disabled = true; this.Manifest.Disabled = true;
this.disabledFile.Delete(); this.disabledFile.Delete();
} }
// This bit converts from ".testing" functionality to using the manifest. // This converts from the ".testing" file feature to the manifest instead.
this.testingFile = LocalPluginManifest.GetTestingFile(this.DllFile);
if (this.testingFile.Exists) if (this.testingFile.Exists)
{ {
this.Manifest.Testing = true; this.Manifest.Testing = true;
this.testingFile.Delete(); this.testingFile.Delete();
} }
var pluginManager = Service<PluginManager>.Get();
this.IsBanned = pluginManager.IsManifestBanned(this.Manifest);
this.SaveManifest(); this.SaveManifest();
} }
@ -157,7 +159,7 @@ namespace Dalamud.Plugin.Internal
/// Gets the AssemblyName plugin, populated during <see cref="Load(PluginLoadReason, bool)"/>. /// Gets the AssemblyName plugin, populated during <see cref="Load(PluginLoadReason, bool)"/>.
/// </summary> /// </summary>
/// <returns>Plugin type.</returns> /// <returns>Plugin type.</returns>
public AssemblyName AssemblyName { get; private set; } = null; public AssemblyName? AssemblyName { get; private set; } = null;
/// <summary> /// <summary>
/// Gets the plugin name, directly from the plugin or if it is not loaded from the manifest. /// Gets the plugin name, directly from the plugin or if it is not loaded from the manifest.
@ -174,11 +176,21 @@ namespace Dalamud.Plugin.Internal
/// </summary> /// </summary>
public bool IsDisabled => this.Manifest.Disabled; public bool IsDisabled => this.Manifest.Disabled;
/// <summary>
/// Gets a value indicating whether this plugin's API level is out of date.
/// </summary>
public bool IsOutdated => this.Manifest.DalamudApiLevel < PluginManager.DalamudApiLevel;
/// <summary> /// <summary>
/// Gets a value indicating whether the plugin is for testing use only. /// Gets a value indicating whether the plugin is for testing use only.
/// </summary> /// </summary>
public bool IsTesting => this.Manifest.IsTestingExclusive || this.Manifest.Testing; public bool IsTesting => this.Manifest.IsTestingExclusive || this.Manifest.Testing;
/// <summary>
/// Gets a value indicating whether this plugin has been banned.
/// </summary>
public bool IsBanned { get; }
/// <summary> /// <summary>
/// Gets a value indicating whether this plugin is dev plugin. /// Gets a value indicating whether this plugin is dev plugin.
/// </summary> /// </summary>
@ -223,6 +235,9 @@ namespace Dalamud.Plugin.Internal
throw new InvalidPluginOperationException($"Unable to load {this.Name}, unload previously faulted, restart Dalamud"); throw new InvalidPluginOperationException($"Unable to load {this.Name}, unload previously faulted, restart Dalamud");
} }
if (pluginManager.IsManifestBanned(this.Manifest))
throw new BannedPluginException($"Unable to load {this.Name}, banned");
if (this.Manifest.ApplicableVersion < startInfo.GameVersion) if (this.Manifest.ApplicableVersion < startInfo.GameVersion)
throw new InvalidPluginOperationException($"Unable to load {this.Name}, no applicable version"); throw new InvalidPluginOperationException($"Unable to load {this.Name}, no applicable version");
@ -255,7 +270,9 @@ namespace Dalamud.Plugin.Internal
{ {
var manifestFile = LocalPluginManifest.GetManifestFile(this.DllFile); var manifestFile = LocalPluginManifest.GetManifestFile(this.DllFile);
if (manifestFile.Exists) if (manifestFile.Exists)
{
this.Manifest = LocalPluginManifest.Load(manifestFile); this.Manifest = LocalPluginManifest.Load(manifestFile);
}
} }
} }

View file

@ -475,6 +475,9 @@ namespace Dalamud.Plugin.Internal
var dllFile = LocalPluginManifest.GetPluginFile(outputDir, repoManifest); var dllFile = LocalPluginManifest.GetPluginFile(outputDir, repoManifest);
var manifestFile = LocalPluginManifest.GetManifestFile(dllFile); var manifestFile = LocalPluginManifest.GetManifestFile(dllFile);
// We need to save the repoManifest due to how the repo fills in some fields that authors are not expected to use.
File.WriteAllText(manifestFile.FullName, JsonConvert.SerializeObject(repoManifest, Formatting.Indented));
// Reload as a local manifest, add some attributes, and save again. // Reload as a local manifest, add some attributes, and save again.
var manifest = LocalPluginManifest.Load(manifestFile); var manifest = LocalPluginManifest.Load(manifestFile);
@ -545,26 +548,31 @@ namespace Dalamud.Plugin.Internal
} }
catch (InvalidPluginException) catch (InvalidPluginException)
{ {
PluginLocations.Remove(plugin.AssemblyName.FullName); PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty);
throw; throw;
} }
catch (BannedPluginException)
{
// Out of date plugins get added so they can be updated.
Log.Information($"Plugin was banned, adding anyways: {dllFile.Name}");
}
catch (Exception ex) catch (Exception ex)
{ {
if (plugin.IsDev) if (plugin.IsDev)
{ {
// Dev plugins always get added to the list so they can be fiddled with in the UI // Dev plugins always get added to the list so they can be fiddled with in the UI
Log.Information(ex, $"Dev plugin failed to load, adding anyways: {dllFile.Name}"); Log.Information(ex, $"Dev plugin failed to load, adding anyways: {dllFile.Name}");
plugin.Disable(); // Disable here, otherwise you can't enable+load later plugin.Disable(); // Disable here, otherwise you can't enable+load later
} }
else if (plugin.Manifest.DalamudApiLevel < DalamudApiLevel) else if (plugin.IsOutdated)
{ {
// Out of date plugins get added so they can be updated. // Out of date plugins get added so they can be updated.
Log.Information(ex, $"Plugin was outdated, adding anyways: {dllFile.Name}"); Log.Information(ex, $"Plugin was outdated, adding anyways: {dllFile.Name}");
// plugin.Disable(); // Don't disable, or it gets deleted next boot. // plugin.Disable(); // Don't disable, or it gets deleted next boot.
} }
else else
{ {
PluginLocations.Remove(plugin.AssemblyName.FullName); PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty);
throw; throw;
} }
} }
@ -584,7 +592,7 @@ namespace Dalamud.Plugin.Internal
throw new InvalidPluginOperationException($"Unable to remove {plugin.Name}, not unloaded"); throw new InvalidPluginOperationException($"Unable to remove {plugin.Name}, not unloaded");
this.InstalledPlugins = this.InstalledPlugins.Remove(plugin); this.InstalledPlugins = this.InstalledPlugins.Remove(plugin);
PluginLocations.Remove(plugin.AssemblyName.FullName); PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty);
this.NotifyInstalledPluginsChanged(); this.NotifyInstalledPluginsChanged();
this.NotifyAvailablePluginsChanged(); this.NotifyAvailablePluginsChanged();
@ -936,7 +944,12 @@ namespace Dalamud.Plugin.Internal
return true; return true;
} }
private bool IsManifestBanned(PluginManifest manifest) /// <summary>
/// Determine if a plugin has been banned by inspecting the manifest.
/// </summary>
/// <param name="manifest">Manifest to inspect.</param>
/// <returns>A value indicating whether the plugin/manifest has been banned.</returns>
public bool IsManifestBanned(PluginManifest manifest)
{ {
return this.bannedPlugins.Any(ban => ban.Name == manifest.InternalName && ban.AssemblyVersion == manifest.AssemblyVersion); return this.bannedPlugins.Any(ban => ban.Name == manifest.InternalName && ban.AssemblyVersion == manifest.AssemblyVersion);
} }

View file

@ -24,10 +24,17 @@ namespace Dalamud.Plugin.Internal.Types
/// <summary> /// <summary>
/// Gets or sets the 3rd party repo URL that this plugin was installed from. Used to display where the plugin was /// Gets or sets the 3rd party repo URL that this plugin was installed from. Used to display where the plugin was
/// sourced from on the installed plugin view. This should not be included in the plugin master. /// sourced from on the installed plugin view. This should not be included in the plugin master. This value is null
/// when installed from the main repo.
/// </summary> /// </summary>
public string InstalledFromUrl { get; set; } public string InstalledFromUrl { get; set; }
/// <summary>
/// Gets a value indicating whether this manifest is associated with a plugin that was installed from a third party
/// repo. Unless the manifest has been manually modified, this is determined by the InstalledFromUrl being null.
/// </summary>
public bool IsThirdParty => !string.IsNullOrEmpty(this.InstalledFromUrl);
/// <summary> /// <summary>
/// Save a plugin manifest to file. /// Save a plugin manifest to file.
/// </summary> /// </summary>

View file

@ -1,173 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{9FDA9A5C-50C6-4333-8DCE-DFEB89363F2A}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>DalamudDebugStub</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;DALAMUDDEBUGSTUB_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;DALAMUDDEBUGSTUB_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;DALAMUDDEBUGSTUB_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;DALAMUDDEBUGSTUB_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="framework.h" />
<ClInclude Include="pch.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -1,118 +0,0 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <stdlib.h>
#include <tchar.h>
#include <cstdio>
#include <DbgHelp.h>
bool isExcept = false;
LONG WINAPI
VectoredHandler(
struct _EXCEPTION_POINTERS* ExceptionInfo
)
{
PEXCEPTION_RECORD Record = ExceptionInfo->ExceptionRecord;
if (Record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
return EXCEPTION_CONTINUE_SEARCH;
//ListProcessThreads(GetCurrentProcessId());
if (!isExcept)
{
isExcept = true;
TCHAR pszMessage[1024] = { 0 };
_stprintf_s(pszMessage, _T("An internal error in Dalamud or a FFXIV plugin occured.\nThe game must close.\n\nDo you wish to save troubleshooting information?\n\nReasoning: 0x%x at 0x%x"), Record->ExceptionCode, Record->ExceptionAddress);
auto res = MessageBox(NULL, pszMessage, L"Dalamud", MB_YESNO | MB_ICONERROR | MB_TOPMOST);
if (res == IDYES)
{
TCHAR fileName[255] = { 0 };
char* pValue;
size_t len;
errno_t err = _dupenv_s(&pValue, &len, "APPDATA");
wchar_t* fullPath = new wchar_t[2048];
// Convert char* string to a wchar_t* string.
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, fullPath, strlen(pValue) + 1, pValue, _TRUNCATE);
SYSTEMTIME t;
GetSystemTime(&t);
_stprintf_s(fileName, _T("MD-%d-%d-%d-%d-%d-%d.dmp"), t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
_tcscat_s(fullPath, 2048, TEXT("\\XIVLauncher\\"));
_tcscat_s(fullPath, 2048, fileName);
HANDLE hFile = CreateFileW(fullPath, GENERIC_READ | GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
{
// Create the minidump
MINIDUMP_EXCEPTION_INFORMATION mdei;
mdei.ThreadId = GetCurrentThreadId();
mdei.ExceptionPointers = ExceptionInfo;
mdei.ClientPointers = TRUE;
BOOL rv = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
hFile, (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithDataSegs | MiniDumpWithThreadInfo), (ExceptionInfo != 0) ? &mdei : 0, 0, 0);
if (!rv)
_stprintf_s(pszMessage, _T("MiniDumpWriteDump failed. Error: %u \n"), GetLastError());
else
_stprintf_s(pszMessage, _T("Minidump created.\n"));
MessageBox(NULL, pszMessage, L"Dalamud", MB_OK | MB_ICONINFORMATION | MB_TOPMOST);
// Close the file
CloseHandle(hFile);
}
else
{
_tprintf(_T("CreateFile failed. Error: %u \n"), GetLastError());
}
}
exit(-1);
}
PCONTEXT Context;
Context = ExceptionInfo->ContextRecord;
#ifdef _AMD64_
Context->Rip++;
#else
Context->Eip++;
#endif
return EXCEPTION_CONTINUE_EXECUTION;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
AddVectoredExceptionHandler(99, VectoredHandler);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

View file

@ -1,5 +0,0 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>

View file

@ -1,5 +0,0 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

View file

@ -1,13 +0,0 @@
// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.
#ifndef PCH_H
#define PCH_H
// add headers that you want to pre-compile here
#include "framework.h"
#endif //PCH_H