diff --git a/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/SharedImmediateTexture.cs b/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/SharedImmediateTexture.cs index 07eb52500..ed76223a3 100644 --- a/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/SharedImmediateTexture.cs +++ b/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/SharedImmediateTexture.cs @@ -1,9 +1,12 @@ +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Dalamud.Interface.Internal; +using Dalamud.Plugin.Internal.Types; using Dalamud.Storage.Assets; using Dalamud.Utility; @@ -42,6 +45,9 @@ internal abstract class SharedImmediateTexture this.FirstRequestedTick = this.LatestRequestedTick = Environment.TickCount64; } + /// Gets the list of owner plugins. + public List OwnerPlugins { get; } = new(); + /// Gets the instance ID. Debug use only. public long InstanceIdForDebug { get; } @@ -274,6 +280,26 @@ internal abstract class SharedImmediateTexture return this.availableOnAccessWrapForApi9; } + /// Adds a plugin to , in a thread-safe way. + /// The plugin to add. + public void AddOwnerPlugin(LocalPlugin plugin) + { + lock (this.OwnerPlugins) + { + if (!this.OwnerPlugins.Contains(plugin)) + { + this.OwnerPlugins.Add(plugin); + this.UnderlyingWrap?.ContinueWith( + r => + { + if (r.IsCompletedSuccessfully) + Service.Get().Blame(r.Result, plugin); + }, + default(CancellationToken)); + } + } + } + /// public override string ToString() => $"{this.GetType().Name}#{this.InstanceIdForDebug}({this.SourcePathForDebug})"; @@ -285,11 +311,31 @@ internal abstract class SharedImmediateTexture } /// Attempts to restore the reference to this texture. - protected void LoadUnderlyingWrap() => - this.UnderlyingWrap = Service.Get().DynamicPriorityTextureLoader.LoadAsync( - this, - this.CreateTextureAsync, - this.LoadCancellationToken); + protected void LoadUnderlyingWrap() + { + int addLen; + lock (this.OwnerPlugins) + { + this.UnderlyingWrap = Service.Get().DynamicPriorityTextureLoader.LoadAsync( + this, + this.CreateTextureAsync, + this.LoadCancellationToken); + + addLen = this.OwnerPlugins.Count; + } + + if (addLen == 0) + return; + this.UnderlyingWrap.ContinueWith( + r => + { + if (!r.IsCompletedSuccessfully) + return; + foreach (var op in this.OwnerPlugins.Take(addLen)) + Service.Get().Blame(r.Result, op); + }, + default(CancellationToken)); + } /// Creates the texture. /// The cancellation token. diff --git a/Dalamud/Interface/Textures/Internal/TextureManager.BlameTracker.cs b/Dalamud/Interface/Textures/Internal/TextureManager.BlameTracker.cs index a401a9a73..5e47d2c8e 100644 --- a/Dalamud/Interface/Textures/Internal/TextureManager.BlameTracker.cs +++ b/Dalamud/Interface/Textures/Internal/TextureManager.BlameTracker.cs @@ -48,6 +48,16 @@ internal sealed partial class TextureManager if (!this.dalamudConfiguration.UseTexturePluginTracking) return textureWrap; + try + { + if (textureWrap.ImGuiHandle == nint.Zero) + return textureWrap; + } + catch (ObjectDisposedException) + { + return textureWrap; + } + using var wrapAux = new WrapAux(textureWrap, true); var blame = BlameTag.From(wrapAux.ResPtr, out var isNew); @@ -75,6 +85,16 @@ internal sealed partial class TextureManager if (!this.dalamudConfiguration.UseTexturePluginTracking) return textureWrap; + try + { + if (textureWrap.ImGuiHandle == nint.Zero) + return textureWrap; + } + catch (ObjectDisposedException) + { + return textureWrap; + } + using var wrapAux = new WrapAux(textureWrap, true); var blame = BlameTag.From(wrapAux.ResPtr, out var isNew); blame.Name = name; diff --git a/Dalamud/Interface/Textures/Internal/TextureManagerPluginScoped.Api9.cs b/Dalamud/Interface/Textures/Internal/TextureManagerPluginScoped.Api9.cs index 21ee1291c..ca5399d0c 100644 --- a/Dalamud/Interface/Textures/Internal/TextureManagerPluginScoped.Api9.cs +++ b/Dalamud/Interface/Textures/Internal/TextureManagerPluginScoped.Api9.cs @@ -14,43 +14,42 @@ internal sealed partial class TextureManagerPluginScoped /// [Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)] [Obsolete("See interface definition.")] - public IDalamudTextureWrap? GetIcon( + string? ITextureProvider.GetIconPath(uint iconId, ITextureProvider.IconFlags flags, ClientLanguage? language) + => this.TryGetIconPath( + new( + iconId, + (flags & ITextureProvider.IconFlags.ItemHighQuality) != 0, + (flags & ITextureProvider.IconFlags.HiRes) != 0, + language), + out var path) + ? path + : null; + + /// + [Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)] + [Obsolete("See interface definition.")] + IDalamudTextureWrap? ITextureProvider.GetIcon( uint iconId, - ITextureProvider.IconFlags flags = ITextureProvider.IconFlags.HiRes, - ClientLanguage? language = null, - bool keepAlive = false) - { - throw new NotImplementedException(); - } + ITextureProvider.IconFlags flags, + ClientLanguage? language, + bool keepAlive) => + this.ManagerOrThrow.Shared.GetFromGameIcon( + new( + iconId, + (flags & ITextureProvider.IconFlags.ItemHighQuality) != 0, + (flags & ITextureProvider.IconFlags.HiRes) != 0, + language)) + .GetAvailableOnAccessWrapForApi9(); /// [Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)] [Obsolete("See interface definition.")] - public string? GetIconPath( - uint iconId, - ITextureProvider.IconFlags flags = ITextureProvider.IconFlags.HiRes, - ClientLanguage? language = null) - { - throw new NotImplementedException(); - } + IDalamudTextureWrap? ITextureProvider.GetTextureFromGame(string path, bool keepAlive) => + this.ManagerOrThrow.Shared.GetFromGame(path).GetAvailableOnAccessWrapForApi9(); /// [Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)] [Obsolete("See interface definition.")] - public IDalamudTextureWrap? GetTextureFromGame( - string path, - bool keepAlive = false) - { - throw new NotImplementedException(); - } - - /// - [Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)] - [Obsolete("See interface definition.")] - public IDalamudTextureWrap? GetTextureFromFile( - FileInfo file, - bool keepAlive = false) - { - throw new NotImplementedException(); - } + IDalamudTextureWrap? ITextureProvider.GetTextureFromFile(FileInfo file, bool keepAlive) => + this.ManagerOrThrow.Shared.GetFromFile(file.FullName).GetAvailableOnAccessWrapForApi9(); } diff --git a/Dalamud/Interface/Textures/Internal/TextureManagerPluginScoped.cs b/Dalamud/Interface/Textures/Internal/TextureManagerPluginScoped.cs index 39b91edda..afdca0f31 100644 --- a/Dalamud/Interface/Textures/Internal/TextureManagerPluginScoped.cs +++ b/Dalamud/Interface/Textures/Internal/TextureManagerPluginScoped.cs @@ -257,25 +257,33 @@ internal sealed partial class TextureManagerPluginScoped /// public ISharedImmediateTexture GetFromGameIcon(in GameIconLookup lookup) { - return this.ManagerOrThrow.Shared.GetFromGameIcon(lookup); + var shared = this.ManagerOrThrow.Shared.GetFromGameIcon(lookup); + shared.AddOwnerPlugin(this.plugin); + return shared; } /// public ISharedImmediateTexture GetFromGame(string path) { - return this.ManagerOrThrow.Shared.GetFromGame(path); + var shared = this.ManagerOrThrow.Shared.GetFromGame(path); + shared.AddOwnerPlugin(this.plugin); + return shared; } /// public ISharedImmediateTexture GetFromFile(string path) { - return this.ManagerOrThrow.Shared.GetFromFile(path); + var shared = this.ManagerOrThrow.Shared.GetFromFile(path); + shared.AddOwnerPlugin(this.plugin); + return shared; } /// public ISharedImmediateTexture GetFromManifestResource(Assembly assembly, string name) { - return this.ManagerOrThrow.Shared.GetFromManifestResource(assembly, name); + var shared = this.ManagerOrThrow.Shared.GetFromManifestResource(assembly, name); + shared.AddOwnerPlugin(this.plugin); + return shared; } ///