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.Collections.Generic;
using System.Linq;
using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Interface.Internal.Windows.StyleEditor;
using Dalamud.Interface.Windowing;
using ImGuiNET;
using JetBrains.Annotations;
using Serilog;
namespace Dalamud.Interface.Internal.Windows
{
@ -14,34 +17,56 @@ namespace Dalamud.Interface.Internal.Windows
private ImGuiColorEditFlags alphaFlags = ImGuiColorEditFlags.None;
private StyleModel workStyle = StyleModel.DalamudStandard;
private int currentSel = 0;
private string initialStyle;
public StyleEditorWindow()
: 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()
{
var config = Service<DalamudConfiguration>.Get();
var style = ImGui.GetStyle();
var a = 0;
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();
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())
@ -64,7 +89,23 @@ namespace Dalamud.Interface.Internal.Windows
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())
@ -74,7 +115,11 @@ namespace Dalamud.Interface.Internal.Windows
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"))
{
@ -178,14 +223,23 @@ namespace Dalamud.Interface.Internal.Windows
if (ImGui.Button("Close"))
{
var newStyle = config.SavedStyles.FirstOrDefault(x => x.Name == this.initialStyle);
newStyle?.Apply();
this.IsOpen = false;
}
ImGui.SameLine();
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>
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>
/// Load a configuration from the provided path.
/// </summary>

View file

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

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
// but there is other state data past this point, and keys beyond here aren't
// generally valid for most things anyway
private const int MaxKeyCodeIndex = 0xA0;
private const int MaxKeyCode = 0xF0;
private readonly IntPtr bufferBase;
private readonly IntPtr indexBase;
private VirtualKey[] validVirtualKeyCache = null;
@ -104,7 +104,7 @@ namespace Dalamud.Game.ClientState.Keys
/// <param name="vkCode">Virtual key code.</param>
/// <returns>If the code is valid.</returns>
public bool IsVirtualKeyValid(int vkCode)
=> vkCode > 0 && vkCode < MaxKeyCodeIndex && this.ConvertVirtualKey(vkCode) != 0;
=> this.ConvertVirtualKey(vkCode) != 0;
/// <inheritdoc cref="IsVirtualKeyValid(int)"/>
public bool IsVirtualKeyValid(VirtualKey vkCode)
@ -136,7 +136,7 @@ namespace Dalamud.Game.ClientState.Keys
/// <returns>Converted value.</returns>
private unsafe byte ConvertVirtualKey(int vkCode)
{
if (vkCode <= 0 || vkCode >= 240)
if (vkCode <= 0 || vkCode >= MaxKeyCode)
return 0;
return *(byte*)(this.indexBase + vkCode);
@ -149,9 +149,6 @@ namespace Dalamud.Game.ClientState.Keys
/// <returns>A reference to the indexed array.</returns>
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);
if (vkCode == 0)

View file

@ -134,6 +134,28 @@ namespace Dalamud.Game
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>
/// Scan for a .data address using a .text function.
/// This is intended to be used with IDA sigs.
@ -160,6 +182,29 @@ namespace Dalamud.Game
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>
/// Scan for a byte signature in the .data section.
/// </summary>
@ -175,6 +220,26 @@ namespace Dalamud.Game
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>
/// Scan for a byte signature in the whole module search area.
/// </summary>
@ -190,6 +255,26 @@ namespace Dalamud.Game
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>
/// Resolve a RVA address.
/// </summary>
@ -224,6 +309,26 @@ namespace Dalamud.Game
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>
/// Free the memory of the copied module search area on object disposal, if applicable.
/// </summary>

View file

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

View file

@ -25,7 +25,6 @@ using Dalamud.Plugin.Internal.Types;
using Dalamud.Utility;
using ImGuiNET;
using ImGuiScene;
using Microsoft.VisualBasic;
namespace Dalamud.Interface.Internal.Windows
{
@ -56,7 +55,7 @@ namespace Dalamud.Interface.Internal.Windows
private string[] testerImagePaths = new string[5];
private string testerIconPath = string.Empty;
private TextureWrap?[]? testerImages;
private TextureWrap?[] testerImages;
private TextureWrap? testerIcon;
private bool testerError = false;
@ -76,9 +75,8 @@ namespace Dalamud.Interface.Internal.Windows
private List<AvailablePluginUpdate> pluginListUpdatable = new();
private bool hasDevPlugins = false;
private bool downloadingIcons = false;
private Dictionary<string, (bool IsDownloaded, TextureWrap?[]? Textures)> pluginImagesMap = new();
private Dictionary<string, (bool IsDownloaded, TextureWrap? Texture)> pluginIconMap = new();
private Dictionary<string, TextureWrap?> pluginIconMap = new();
private Dictionary<string, TextureWrap?[]> pluginImagesMap = new();
private string searchText = string.Empty;
@ -197,8 +195,6 @@ namespace Dalamud.Interface.Internal.Windows
{
this.pluginIconMap.Clear();
this.pluginImagesMap.Clear();
this.DownloadPluginIcons();
}
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");
}
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 (manifest.ImageUrls.Count > 5)
{
Log.Warning($"Plugin {manifest.InternalName} has too many images");
return manifest.ImageUrls.Take(5).ToList();
}
return manifest.ImageUrls;
}
var output = new List<string>();
for (var i = 1; i <= 5; i++)
@ -223,6 +227,36 @@ namespace Dalamud.Interface.Internal.Windows
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()
{
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()
{
var sectionSize = ImGuiHelpers.GlobalScale * 66;
@ -800,7 +833,7 @@ namespace Dalamud.Interface.Internal.Windows
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();
@ -837,12 +870,20 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.SetCursorPos(startCursor);
var hasIcon = this.pluginIconMap.TryGetValue(manifest.InternalName, out var icon);
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);
@ -868,13 +909,14 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.SameLine();
var cursor = ImGui.GetCursorPos();
// Name
ImGui.Text(label);
// Download count
var downloadCountText = manifest.DownloadCount > 0
? Locs.PluginBody_AuthorWithDownloadCount(manifest.Author, manifest.DownloadCount)
: Locs.PluginBody_AuthorWithDownloadCountUnavailable(manifest.Author);
? Locs.PluginBody_AuthorWithDownloadCount(manifest.Author, manifest.DownloadCount)
: Locs.PluginBody_AuthorWithDownloadCountUnavailable(manifest.Author);
ImGui.SameLine();
ImGui.TextColored(ImGuiColors.DalamudGrey3, downloadCountText);
@ -927,7 +969,8 @@ namespace Dalamud.Interface.Internal.Windows
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)
configuration.SeenPluginInternalName.Add(manifest.InternalName);
@ -996,7 +1039,7 @@ namespace Dalamud.Interface.Internal.Windows
ImGuiHelpers.ScaledDummy(5);
if (this.DrawPluginImages(manifest, index, manifest.SourceRepo.IsThirdParty))
if (this.DrawPluginImages(null, manifest, isThirdParty, index))
ImGuiHelpers.ScaledDummy(5);
ImGui.Unindent();
@ -1124,15 +1167,22 @@ namespace Dalamud.Interface.Internal.Windows
}
// Outdated API level
if (plugin.Manifest.DalamudApiLevel < PluginManager.DalamudApiLevel)
if (plugin.IsOutdated)
{
label += Locs.PluginTitleMod_OutdatedError;
trouble = true;
}
// Banned
if (plugin.IsBanned)
{
label += Locs.PluginTitleMod_BannedError;
trouble = true;
}
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))
configuration.SeenPluginInternalName.Add(plugin.Manifest.InternalName);
@ -1154,7 +1204,7 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.SameLine();
ImGui.TextColored(ImGuiColors.DalamudGrey3, downloadText);
var isThirdParty = !string.IsNullOrEmpty(manifest.InstalledFromUrl);
var isThirdParty = manifest.IsThirdParty;
// Installed from
if (plugin.IsDev)
@ -1174,13 +1224,20 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.TextWrapped(manifest.Description);
}
if (plugin.Manifest.DalamudApiLevel < PluginManager.DalamudApiLevel)
if (plugin.IsOutdated)
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
ImGui.TextWrapped(Locs.PluginBody_Outdated);
ImGui.PopStyleColor();
}
if (plugin.IsBanned)
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
ImGui.TextWrapped(Locs.PluginBody_Banned);
ImGui.PopStyleColor();
}
// Available commands (if loaded)
if (plugin.IsLoaded)
{
@ -1201,6 +1258,7 @@ namespace Dalamud.Interface.Internal.Windows
// Controls
this.DrawPluginControlButton(plugin);
this.DrawDevPluginButtons(plugin);
this.DrawDeletePluginButton(plugin);
this.DrawVisitRepoUrlButton(plugin.Manifest.RepoUrl);
if (availablePluginUpdate != default)
@ -1217,9 +1275,8 @@ namespace Dalamud.Interface.Internal.Windows
ImGuiHelpers.ScaledDummy(5);
this.DrawPluginImages(manifest, index, isThirdParty);
ImGuiHelpers.ScaledDummy(5);
if (this.DrawPluginImages(plugin, manifest, isThirdParty, index))
ImGuiHelpers.ScaledDummy(5);
ImGui.Unindent();
}
@ -1263,7 +1320,7 @@ namespace Dalamud.Interface.Internal.Windows
var disabled = this.updateStatus == OperationStatus.InProgress || this.installStatus == OperationStatus.InProgress;
// 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)
{
@ -1411,7 +1468,6 @@ namespace Dalamud.Interface.Internal.Windows
private void DrawDevPluginButtons(LocalPlugin localPlugin)
{
var configuration = Service<DalamudConfiguration>.Get();
var pluginManager = Service<PluginManager>.Get();
if (localPlugin is LocalDevPlugin plugin)
{
@ -1454,33 +1510,40 @@ namespace Dalamud.Interface.Internal.Windows
{
ImGui.SetTooltip(Locs.PluginButtonToolTip_AutomaticReloading);
}
}
}
// Delete
if (plugin.State == PluginState.Unloaded)
private void DrawDeletePluginButton(LocalPlugin plugin)
{
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();
if (ImGuiComponents.IconButton(FontAwesomeIcon.TrashAlt))
{
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);
}
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.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;
}
if (!images.IsDownloaded)
return false;
if (images.Textures == null)
if (imageTextures.Length == 0)
return false;
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 (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}";
var image = images.Textures[i];
if (image == null)
continue;
if (ImGui.ImageButton(image.ImGuiHandle, new Vector2(image.Width, image.Height)))
ImGui.CloseCurrentPopup();
ImGui.PushStyleVar(ImGuiStyleVar.PopupBorderSize, 0);
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, Vector2.Zero);
ImGui.EndPopup();
}
if (ImGui.BeginPopup(popupId))
{
if (ImGui.ImageButton(image.ImGuiHandle, new Vector2(image.Width, image.Height)))
ImGui.CloseCurrentPopup();
ImGui.PopStyleVar(3);
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)))
ImGui.OpenPopup(popupId);
ImGui.PopStyleVar();
if (i < images.Textures.Length - 1)
{
ImGui.SameLine();
ImGuiHelpers.ScaledDummy(5);
ImGui.SameLine();
}
if (i < imageTextures.Length - 1)
{
ImGui.SameLine();
ImGuiHelpers.ScaledDummy(5);
ImGui.SameLine();
}
}
}
@ -1612,8 +1672,6 @@ namespace Dalamud.Interface.Internal.Windows
.ToList();
this.pluginListUpdatable = pluginManager.UpdatablePlugins.ToList();
this.ResortPlugins();
this.DownloadPluginIcons();
}
private void OnInstalledPluginsChanged()
@ -1624,8 +1682,6 @@ namespace Dalamud.Interface.Internal.Windows
this.pluginListUpdatable = pluginManager.UpdatablePlugins.ToList();
this.hasDevPlugins = this.pluginListInstalled.Any(plugin => plugin.IsDev);
this.ResortPlugins();
this.DownloadPluginIcons();
}
private void ResortPlugins()
@ -1705,133 +1761,173 @@ namespace Dalamud.Interface.Internal.Windows
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;
}
this.downloadingIcons = true;
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}");
var useTesting = pluginManager.UseTesting(manifest);
var url = GetPluginIconUrl(manifest, isThirdParty, useTesting);
if (url != null)
{
Log.Verbose($"Downloading icon for {manifest.InternalName} from {url}");
var data = await this.httpClient.GetAsync(url);
if (data.StatusCode == HttpStatusCode.NotFound)
return;
data.EnsureSuccessStatusCode();
var icon = interfaceManager.LoadImage(await data.Content.ReadAsByteArrayAsync());
if (icon != null)
{
if (icon.Height > PluginIconHeight || icon.Width > PluginIconWidth)
{
Log.Error($"Icon at {manifest.IconUrl} was not of the correct resolution.");
return;
}
if (!ValidateIcon(icon, url))
return;
if (icon.Height != icon.Width)
{
Log.Error($"Icon at {manifest.IconUrl} was not square.");
return;
}
this.pluginIconMap[manifest.InternalName] = icon;
Log.Verbose($"Plugin icon for {manifest.InternalName} downloaded");
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 pluginManager = Service<PluginManager>.Get();
Log.Verbose($"Downloading images for {manifest.InternalName}");
this.pluginImagesMap.Add(manifest.InternalName, (false, null));
var urls = GetPluginImageUrls(manifest, isThirdParty, pluginManager.UseTesting(manifest));
var didAny = false;
if (urls != null)
static bool ValidateImage(TextureWrap image, string loc)
{
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.");
return;
Log.Error($"Image at {loc} was not of the correct resolution.");
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];
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)
continue;
data.EnsureSuccessStatusCode();
var image = interfaceManager.LoadImage(await data.Content.ReadAsByteArrayAsync());
if (image == null)
{
return;
}
if (image.Height != PluginImageHeight || image.Width != PluginImageWidth)
{
Log.Error($"Image at {urls[i]} was not of the correct resolution.");
return;
}
didAny = true;
if (!ValidateImage(image, url))
continue;
Log.Verbose($"Plugin image{i + 1} for {manifest.InternalName} downloaded");
pluginImages[i] = image;
didAny = true;
}
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")]
@ -1919,6 +2015,8 @@ namespace Dalamud.Interface.Internal.Windows
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!");
#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_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
#region Plugin buttons

View file

@ -59,6 +59,7 @@ namespace Dalamud.Interface.Internal.Windows
private bool printPluginsWelcomeMsg;
private bool autoUpdatePlugins;
private bool doButtonsSystemMenu;
private bool disableRmtFiltering;
#region Experimental
@ -99,6 +100,7 @@ namespace Dalamud.Interface.Internal.Windows
this.printPluginsWelcomeMsg = configuration.PrintPluginsWelcomeMsg;
this.autoUpdatePlugins = configuration.AutoUpdatePlugins;
this.doButtonsSystemMenu = configuration.DoButtonsSystemMenu;
this.disableRmtFiltering = configuration.DisableRmtFiltering;
this.languages = Localization.ApplicableLangCodes.Prepend("en").ToArray();
try
@ -238,6 +240,9 @@ namespace Dalamud.Interface.Internal.Windows
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.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()
@ -689,6 +694,7 @@ namespace Dalamud.Interface.Internal.Windows
configuration.PrintPluginsWelcomeMsg = this.printPluginsWelcomeMsg;
configuration.AutoUpdatePlugins = this.autoUpdatePlugins;
configuration.DoButtonsSystemMenu = this.doButtonsSystemMenu;
configuration.DisableRmtFiltering = this.disableRmtFiltering;
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;
}
var notificationManager = Service<NotificationManager>.Get();
try
{
this.Reload();
Service<NotificationManager>.Get()
.AddNotification(
$"The DevPlugin '{this.Name} was reloaded successfully.", "Plugin reloaded!", NotificationType.Success);
notificationManager.AddNotification($"The DevPlugin '{this.Name} was reloaded successfully.", "Plugin reloaded!", NotificationType.Success);
}
catch (Exception ex)
{
Log.Error(ex, "DevPlugin reload failed.");
Service<NotificationManager>.Get()
.AddNotification(
$"The DevPlugin '{this.Name} could not be reloaded.", "Plugin reload failed!", NotificationType.Error);
notificationManager.AddNotification($"The DevPlugin '{this.Name} could not be reloaded.", "Plugin reload failed!", NotificationType.Error);
}
},
this.fileWatcherTokenSource.Token);

View file

@ -86,10 +86,8 @@ namespace Dalamud.Plugin.Internal
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.disabledFile = LocalPluginManifest.GetDisabledFile(this.DllFile);
this.testingFile = LocalPluginManifest.GetTestingFile(this.DllFile);
// If the parameter manifest was 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.
// We'll update the name property after it can be retrieved from the instance.
var manifestFile = LocalPluginManifest.GetManifestFile(this.DllFile);
this.Manifest.Save(manifestFile);
this.Manifest.Save(this.manifestFile);
}
else
{
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)
{
this.Manifest.Disabled = true;
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)
{
this.Manifest.Testing = true;
this.testingFile.Delete();
}
var pluginManager = Service<PluginManager>.Get();
this.IsBanned = pluginManager.IsManifestBanned(this.Manifest);
this.SaveManifest();
}
@ -157,7 +159,7 @@ namespace Dalamud.Plugin.Internal
/// Gets the AssemblyName plugin, populated during <see cref="Load(PluginLoadReason, bool)"/>.
/// </summary>
/// <returns>Plugin type.</returns>
public AssemblyName AssemblyName { get; private set; } = null;
public AssemblyName? AssemblyName { get; private set; } = null;
/// <summary>
/// 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>
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>
/// Gets a value indicating whether the plugin is for testing use only.
/// </summary>
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>
/// Gets a value indicating whether this plugin is dev plugin.
/// </summary>
@ -223,6 +235,9 @@ namespace Dalamud.Plugin.Internal
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)
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);
if (manifestFile.Exists)
{
this.Manifest = LocalPluginManifest.Load(manifestFile);
}
}
}

View file

@ -475,6 +475,9 @@ namespace Dalamud.Plugin.Internal
var dllFile = LocalPluginManifest.GetPluginFile(outputDir, repoManifest);
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.
var manifest = LocalPluginManifest.Load(manifestFile);
@ -545,26 +548,31 @@ namespace Dalamud.Plugin.Internal
}
catch (InvalidPluginException)
{
PluginLocations.Remove(plugin.AssemblyName.FullName);
PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty);
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)
{
if (plugin.IsDev)
{
// 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
}
else if (plugin.Manifest.DalamudApiLevel < DalamudApiLevel)
else if (plugin.IsOutdated)
{
// 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.
}
else
{
PluginLocations.Remove(plugin.AssemblyName.FullName);
PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty);
throw;
}
}
@ -584,7 +592,7 @@ namespace Dalamud.Plugin.Internal
throw new InvalidPluginOperationException($"Unable to remove {plugin.Name}, not unloaded");
this.InstalledPlugins = this.InstalledPlugins.Remove(plugin);
PluginLocations.Remove(plugin.AssemblyName.FullName);
PluginLocations.Remove(plugin.AssemblyName?.FullName ?? string.Empty);
this.NotifyInstalledPluginsChanged();
this.NotifyAvailablePluginsChanged();
@ -936,7 +944,12 @@ namespace Dalamud.Plugin.Internal
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);
}

View file

@ -24,10 +24,17 @@ namespace Dalamud.Plugin.Internal.Types
/// <summary>
/// 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>
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>
/// Save a plugin manifest to file.
/// </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