From 949a6072ce5846aa522c2130185dbe669dc96c51 Mon Sep 17 00:00:00 2001 From: Raymond Date: Wed, 22 Sep 2021 19:34:23 -0400 Subject: [PATCH 1/6] Allow devIcons to load images from the manifest --- .../Internal/Windows/PluginInstallerWindow.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs index f663cd168..beb5e0253 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs @@ -205,11 +205,11 @@ namespace Dalamud.Interface.Internal.Windows return MainRepoImageUrl.Format(isTesting ? "testing" : "plugins", manifest.InternalName, "icon.png"); } - private static List GetPluginImageUrls(PluginManifest manifest, bool isThirdParty, bool isTesting) + private static List? GetPluginImageUrls(PluginManifest manifest, bool isThirdParty, bool isTesting) { if (isThirdParty) { - if (manifest.ImageUrls.Count > 5) + if (manifest.ImageUrls?.Count > 5) { Log.Warning($"Plugin {manifest.InternalName} has too many images"); return manifest.ImageUrls.Take(5).ToList(); @@ -1802,7 +1802,9 @@ namespace Dalamud.Interface.Internal.Windows Log.Verbose($"Plugin icon for {manifest.InternalName} loaded from disk"); } - return; + // Dev plugins are likely going to look like a main repo plugin, the InstalledFrom field is going to be null. + // So instead, set the value manually so we download from the urls specified. + isThirdParty = true; } var useTesting = pluginManager.UseTesting(manifest); @@ -1885,8 +1887,9 @@ namespace Dalamud.Interface.Internal.Windows } } - // Dev plugins are loaded from disk only - return; + // Dev plugins are likely going to look like a main repo plugin, the InstalledFrom field is going to be null. + // So instead, set the value manually so we download from the urls specified. + isThirdParty = true; } var useTesting = pluginManager.UseTesting(manifest); From 6527ebed01ef812b099b671690f015e8c8b75ca1 Mon Sep 17 00:00:00 2001 From: Raymond Date: Wed, 22 Sep 2021 20:19:58 -0400 Subject: [PATCH 2/6] Log STBI error source --- .../Internal/Windows/PluginInstallerWindow.cs | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs index beb5e0253..235612e7a 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs @@ -1786,6 +1786,17 @@ namespace Dalamud.Interface.Internal.Windows return true; } + static bool TryLoadIcon(byte[] bytes, PluginManifest manifest, InterfaceManager interfaceManager, out TextureWrap image) + { + image = interfaceManager.LoadImage(bytes); + + var success = image != null; + if (!success) + Log.Error($"Could not load icon for {manifest.InternalName}"); + + return success; + } + if (plugin != null && plugin.IsDev) { var file = GetPluginIconFileInfo(plugin); @@ -1793,7 +1804,9 @@ namespace Dalamud.Interface.Internal.Windows { Log.Verbose($"Fetching icon for {manifest.InternalName} from {file.FullName}"); - var icon = interfaceManager.LoadImage(file.FullName); + var bytes = await File.ReadAllBytesAsync(file.FullName); + if (!TryLoadIcon(bytes, manifest, interfaceManager, out var icon)) + return; if (!ValidateIcon(icon, file.FullName)) return; @@ -1819,7 +1832,9 @@ namespace Dalamud.Interface.Internal.Windows data.EnsureSuccessStatusCode(); - var icon = interfaceManager.LoadImage(await data.Content.ReadAsByteArrayAsync()); + var bytes = await data.Content.ReadAsByteArrayAsync(); + if (!TryLoadIcon(bytes, manifest, interfaceManager, out var icon)) + return; if (!ValidateIcon(icon, url)) return; @@ -1852,6 +1867,17 @@ namespace Dalamud.Interface.Internal.Windows return true; } + static bool TryLoadImage(int i, byte[] bytes, PluginManifest manifest, InterfaceManager interfaceManager, out TextureWrap image) + { + image = interfaceManager.LoadImage(bytes); + + var success = image != null; + if (!success) + Log.Error($"Could not load image{i + 1} for {manifest.InternalName}"); + + return success; + } + if (plugin != null && plugin.IsDev) { var files = GetPluginImageFileInfos(plugin); @@ -1868,7 +1894,9 @@ namespace Dalamud.Interface.Internal.Windows Log.Verbose($"Loading image{i + 1} for {manifest.InternalName} from {file.FullName}"); - var image = interfaceManager.LoadImage(await File.ReadAllBytesAsync(file.FullName)); + var bytes = await File.ReadAllBytesAsync(file.FullName); + if (!TryLoadImage(i, bytes, manifest, interfaceManager, out var image)) + continue; if (!ValidateImage(image, file.FullName)) continue; @@ -1911,7 +1939,9 @@ namespace Dalamud.Interface.Internal.Windows data.EnsureSuccessStatusCode(); - var image = interfaceManager.LoadImage(await data.Content.ReadAsByteArrayAsync()); + var bytes = await data.Content.ReadAsByteArrayAsync(); + if (!TryLoadImage(i, bytes, manifest, interfaceManager, out var image)) + continue; if (!ValidateImage(image, url)) continue; From 347ae4b679aee0cd1bc893115c9b9bef610eec47 Mon Sep 17 00:00:00 2001 From: Raymond Date: Thu, 23 Sep 2021 07:40:26 -0400 Subject: [PATCH 3/6] Move icon/image methods near usage, remove static --- .../Internal/Windows/PluginInstallerWindow.cs | 120 +++++++++--------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs index 235612e7a..142cc7759 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs @@ -197,66 +197,6 @@ namespace Dalamud.Interface.Internal.Windows this.pluginImagesMap.Clear(); } - private static string? GetPluginIconUrl(PluginManifest manifest, bool isThirdParty, bool isTesting) - { - if (isThirdParty) - return manifest.IconUrl; - - return MainRepoImageUrl.Format(isTesting ? "testing" : "plugins", manifest.InternalName, "icon.png"); - } - - private static List? 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(); - for (var i = 1; i <= 5; i++) - { - output.Add(MainRepoImageUrl.Format(isTesting ? "testing" : "plugins", manifest.InternalName, $"image{i}.png")); - } - - 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 GetPluginImageFileInfos(LocalPlugin? plugin) - { - var pluginDir = plugin.DllFile.Directory; - var output = new List(); - 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(); @@ -1963,6 +1903,66 @@ namespace Dalamud.Interface.Internal.Windows Log.Verbose($"Images for {manifest.InternalName} are not available"); } + private string? GetPluginIconUrl(PluginManifest manifest, bool isThirdParty, bool isTesting) + { + if (isThirdParty) + return manifest.IconUrl; + + return MainRepoImageUrl.Format(isTesting ? "testing" : "plugins", manifest.InternalName, "icon.png"); + } + + private List? 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(); + for (var i = 1; i <= 5; i++) + { + output.Add(MainRepoImageUrl.Format(isTesting ? "testing" : "plugins", manifest.InternalName, $"image{i}.png")); + } + + return output; + } + + private 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 List GetPluginImageFileInfos(LocalPlugin? plugin) + { + var pluginDir = plugin.DllFile.Directory; + var output = new List(); + 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; + } + [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "Disregard here")] private static class Locs { From 3790fb44c04c70bd69ba218c74ed146e93055b3b Mon Sep 17 00:00:00 2001 From: Raymond Date: Thu, 23 Sep 2021 07:54:09 -0400 Subject: [PATCH 4/6] merge internal methods, improve logging --- .../Internal/Windows/PluginInstallerWindow.cs | 84 +++++++------------ 1 file changed, 31 insertions(+), 53 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs index 142cc7759..0d866ca1b 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs @@ -1706,49 +1706,40 @@ namespace Dalamud.Interface.Internal.Windows var interfaceManager = Service.Get(); var pluginManager = Service.Get(); - static bool ValidateIcon(TextureWrap icon, string loc) + static bool TryLoadIcon(byte[] bytes, string loc, PluginManifest manifest, InterfaceManager interfaceManager, out TextureWrap icon) { - if (icon == null) - return false; + icon = interfaceManager.LoadImage(bytes); - if (icon.Height > PluginIconHeight || icon.Width > PluginIconWidth) + if (icon == null) { - Log.Error($"Icon at {loc} was not of the correct resolution."); + Log.Error($"Could not load icon for {manifest.InternalName} at {loc}"); + return false; + } + + if (icon.Width > PluginIconWidth || icon.Height > PluginIconHeight) + { + Log.Error($"Icon for {manifest.InternalName} at {loc} was larger than the maximum allowed resolution ({PluginIconWidth}x{PluginIconHeight})."); return false; } if (icon.Height != icon.Width) { - Log.Error($"Icon at {loc} was not square."); + Log.Error($"Icon for {manifest.InternalName} at {loc} was not square."); return false; } return true; } - static bool TryLoadIcon(byte[] bytes, PluginManifest manifest, InterfaceManager interfaceManager, out TextureWrap image) - { - image = interfaceManager.LoadImage(bytes); - - var success = image != null; - if (!success) - Log.Error($"Could not load icon for {manifest.InternalName}"); - - return success; - } - if (plugin != null && plugin.IsDev) { - var file = GetPluginIconFileInfo(plugin); + var file = this.GetPluginIconFileInfo(plugin); if (file != null) { Log.Verbose($"Fetching icon for {manifest.InternalName} from {file.FullName}"); var bytes = await File.ReadAllBytesAsync(file.FullName); - if (!TryLoadIcon(bytes, manifest, interfaceManager, out var icon)) - return; - - if (!ValidateIcon(icon, file.FullName)) + if (!TryLoadIcon(bytes, file.FullName, manifest, interfaceManager, out var icon)) return; this.pluginIconMap[manifest.InternalName] = icon; @@ -1761,7 +1752,7 @@ namespace Dalamud.Interface.Internal.Windows } var useTesting = pluginManager.UseTesting(manifest); - var url = GetPluginIconUrl(manifest, isThirdParty, useTesting); + var url = this.GetPluginIconUrl(manifest, isThirdParty, useTesting); if (url != null) { Log.Verbose($"Downloading icon for {manifest.InternalName} from {url}"); @@ -1773,10 +1764,7 @@ namespace Dalamud.Interface.Internal.Windows data.EnsureSuccessStatusCode(); var bytes = await data.Content.ReadAsByteArrayAsync(); - if (!TryLoadIcon(bytes, manifest, interfaceManager, out var icon)) - return; - - if (!ValidateIcon(icon, url)) + if (!TryLoadIcon(bytes, url, manifest, interfaceManager, out var icon)) return; this.pluginIconMap[manifest.InternalName] = icon; @@ -1793,34 +1781,28 @@ namespace Dalamud.Interface.Internal.Windows var interfaceManager = Service.Get(); var pluginManager = Service.Get(); - static bool ValidateImage(TextureWrap image, string loc) + static bool TryLoadImage(int i, byte[] bytes, string loc, PluginManifest manifest, InterfaceManager interfaceManager, out TextureWrap image) { - if (image == null) - return false; + image = interfaceManager.LoadImage(bytes); - if (image.Height != PluginImageHeight || image.Width != PluginImageWidth) + if (image == null) { - Log.Error($"Image at {loc} was not of the correct resolution."); + Log.Error($"Could not load image{i + 1} for {manifest.InternalName} at {loc}"); + return false; + } + + if (image.Width > PluginImageWidth || image.Height > PluginImageHeight) + { + Log.Error($"Image{i + 1} for {manifest.InternalName} at {loc} was larger than the maximum allowed resolution ({PluginImageWidth}x{PluginImageHeight})."); return false; } return true; } - static bool TryLoadImage(int i, byte[] bytes, PluginManifest manifest, InterfaceManager interfaceManager, out TextureWrap image) - { - image = interfaceManager.LoadImage(bytes); - - var success = image != null; - if (!success) - Log.Error($"Could not load image{i + 1} for {manifest.InternalName}"); - - return success; - } - if (plugin != null && plugin.IsDev) { - var files = GetPluginImageFileInfos(plugin); + var files = this.GetPluginImageFileInfos(plugin); if (files != null) { var didAny = false; @@ -1833,16 +1815,14 @@ namespace Dalamud.Interface.Internal.Windows continue; Log.Verbose($"Loading image{i + 1} for {manifest.InternalName} from {file.FullName}"); - var bytes = await File.ReadAllBytesAsync(file.FullName); - if (!TryLoadImage(i, bytes, manifest, interfaceManager, out var image)) - continue; - if (!ValidateImage(image, file.FullName)) + if (!TryLoadImage(i, bytes, file.FullName, manifest, interfaceManager, out var image)) continue; Log.Verbose($"Plugin image{i + 1} for {manifest.InternalName} loaded from disk"); pluginImages[i] = image; + didAny = true; } @@ -1861,7 +1841,7 @@ namespace Dalamud.Interface.Internal.Windows } var useTesting = pluginManager.UseTesting(manifest); - var urls = GetPluginImageUrls(manifest, isThirdParty, useTesting); + var urls = this.GetPluginImageUrls(manifest, isThirdParty, useTesting); if (urls != null) { var didAny = false; @@ -1880,14 +1860,12 @@ namespace Dalamud.Interface.Internal.Windows data.EnsureSuccessStatusCode(); var bytes = await data.Content.ReadAsByteArrayAsync(); - if (!TryLoadImage(i, bytes, manifest, interfaceManager, out var image)) - continue; - - if (!ValidateImage(image, url)) + if (!TryLoadImage(i, bytes, url, manifest, interfaceManager, out var image)) continue; Log.Verbose($"Plugin image{i + 1} for {manifest.InternalName} downloaded"); pluginImages[i] = image; + didAny = true; } From 4a4aa2d85cd84df398fcbe42ded97bb660d97198 Mon Sep 17 00:00:00 2001 From: Raymond Date: Thu, 23 Sep 2021 07:50:36 -0400 Subject: [PATCH 5/6] catch invalid URIs in icon and images fields --- .../Internal/Windows/PluginInstallerWindow.cs | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs index 0d866ca1b..b793139a9 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs @@ -1757,7 +1757,17 @@ namespace Dalamud.Interface.Internal.Windows { Log.Verbose($"Downloading icon for {manifest.InternalName} from {url}"); - var data = await this.httpClient.GetAsync(url); + HttpResponseMessage data; + try + { + data = await this.httpClient.GetAsync(url); + } + catch (InvalidOperationException) + { + Log.Error($"Plugin icon for {manifest.InternalName} has an Invalid URI"); + return; + } + if (data.StatusCode == HttpStatusCode.NotFound) return; @@ -1773,7 +1783,7 @@ namespace Dalamud.Interface.Internal.Windows return; } - Log.Verbose($"Icon for {manifest.InternalName} is not available"); + Log.Verbose($"Plugin icon for {manifest.InternalName} is not available"); } private async Task DownloadPluginImagesAsync(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty) @@ -1793,7 +1803,7 @@ namespace Dalamud.Interface.Internal.Windows if (image.Width > PluginImageWidth || image.Height > PluginImageHeight) { - Log.Error($"Image{i + 1} for {manifest.InternalName} at {loc} was larger than the maximum allowed resolution ({PluginImageWidth}x{PluginImageHeight})."); + Log.Error($"Plugin image{i + 1} for {manifest.InternalName} at {loc} was larger than the maximum allowed resolution ({PluginImageWidth}x{PluginImageHeight})."); return false; } @@ -1852,7 +1862,16 @@ namespace Dalamud.Interface.Internal.Windows Log.Verbose($"Downloading image{i + 1} for {manifest.InternalName} from {url}"); - var data = await this.httpClient.GetAsync(url); + HttpResponseMessage data; + try + { + data = await this.httpClient.GetAsync(url); + } + catch (InvalidOperationException) + { + Log.Error($"Plugin image{i + 1} for {manifest.InternalName} has an Invalid URI"); + continue; + } if (data.StatusCode == HttpStatusCode.NotFound) continue; From da6ee0252d43a72dad4989c2ed19848da6d80937 Mon Sep 17 00:00:00 2001 From: Raymond Date: Thu, 23 Sep 2021 11:56:05 -0400 Subject: [PATCH 6/6] scale undersized plugin images without losing dimensions --- .../Internal/Windows/PluginInstallerWindow.cs | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs index b793139a9..7b0a64384 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs @@ -665,7 +665,21 @@ namespace Dalamud.Interface.Internal.Windows ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, Vector2.Zero); - if (ImGui.ImageButton(image.ImGuiHandle, ImGuiHelpers.ScaledVector2(image.Width / thumbFactor, image.Height / thumbFactor))) + float xAct = image.Width; + float yAct = image.Height; + float xMax = PluginImageWidth; + float yMax = PluginImageHeight; + + // scale image if undersized + if (xAct < xMax && yAct < yMax) + { + var scale = Math.Min(xMax / xAct, yMax / yAct); + xAct *= scale; + yAct *= scale; + } + + var size = ImGuiHelpers.ScaledVector2(xAct / thumbFactor, yAct / thumbFactor); + if (ImGui.ImageButton(image.ImGuiHandle, size)) ImGui.OpenPopup(popupId); ImGui.PopStyleVar(); @@ -1560,7 +1574,21 @@ namespace Dalamud.Interface.Internal.Windows ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, Vector2.Zero); - if (ImGui.ImageButton(image.ImGuiHandle, ImGuiHelpers.ScaledVector2(image.Width / thumbFactor, image.Height / thumbFactor))) + float xAct = image.Width; + float yAct = image.Height; + float xMax = PluginImageWidth; + float yMax = PluginImageHeight; + + // scale image if undersized + if (xAct < xMax && yAct < yMax) + { + var scale = Math.Min(xMax / xAct, yMax / yAct); + xAct *= scale; + yAct *= scale; + } + + var size = ImGuiHelpers.ScaledVector2(xAct / thumbFactor, yAct / thumbFactor); + if (ImGui.ImageButton(image.ImGuiHandle, size)) ImGui.OpenPopup(popupId); ImGui.PopStyleVar();