mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-02-23 08:17:47 +01:00
merge
This commit is contained in:
commit
c925611674
19 changed files with 540 additions and 561 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 &&
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
22
Dalamud/Plugin/Internal/Exceptions/BannedPluginException.cs
Normal file
22
Dalamud/Plugin/Internal/Exceptions/BannedPluginException.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue