Make DtrBar more threadsafe (#1978)

* Changed DtrBar to use ReaderWriterLockSlim so that there exists only one storage of entries, preventing possible desync.
* DtrBarEntry will now hold a reference to the LocalPlugin that created the entry, so that DtrBarPluginScoped can defer plugin related handling to the main service.
* Marked DtrBarEntry class itself to be turned internal in API 11.
* Made IDtrBar.Entries return an immutable copy of underlying list of DtrBar entries, that will be freshly created whenever the list changes.
This commit is contained in:
srkizer 2024-07-28 21:14:37 +09:00 committed by GitHub
parent a7ab3b9def
commit c25f13261d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 385 additions and 207 deletions

View file

@ -15,13 +15,11 @@ using Dalamud.Configuration;
using Dalamud.Configuration.Internal;
using Dalamud.Game;
using Dalamud.Game.Gui;
using Dalamud.Game.Gui.Dtr;
using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Interface;
using Dalamud.Interface.Internal;
using Dalamud.Interface.Internal.Windows.PluginInstaller;
using Dalamud.IoC;
using Dalamud.Logging.Internal;
using Dalamud.Networking.Http;
@ -1123,10 +1121,6 @@ internal class PluginManager : IInternalDisposableService
return updateStatus;
}
// We need to handle removed DTR nodes here, as otherwise, plugins will not be able to re-add their bar entries after updates.
var dtr = Service<DtrBar>.Get();
dtr.HandleRemovedNodes();
try
{
await this.InstallPluginInternalAsync(metadata.UpdateManifest, metadata.UseTesting, PluginLoadReason.Update, updateStream, workingPluginId);

View file

@ -6,8 +6,6 @@ using System.Threading.Tasks;
using Dalamud.Configuration.Internal;
using Dalamud.Game;
using Dalamud.Game.Gui;
using Dalamud.Game.Gui.Dtr;
using Dalamud.Interface.Internal;
using Dalamud.IoC.Internal;
using Dalamud.Logging.Internal;
@ -15,7 +13,6 @@ using Dalamud.Plugin.Internal.Exceptions;
using Dalamud.Plugin.Internal.Loader;
using Dalamud.Plugin.Internal.Profiles;
using Dalamud.Plugin.Internal.Types.Manifest;
using Dalamud.Utility;
namespace Dalamud.Plugin.Internal.Types;
@ -540,9 +537,6 @@ internal class LocalPlugin : IDisposable
}
finally
{
// We need to handle removed DTR nodes here, as otherwise, plugins will not be able to re-add their bar entries after updates.
Service<DtrBar>.GetNullable()?.HandleRemovedNodes();
this.pluginLoadStateLock.Release();
}
}

View file

@ -2,7 +2,6 @@
using Dalamud.Game.Gui.Dtr;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Utility;
namespace Dalamud.Plugin.Services;
@ -12,10 +11,13 @@ namespace Dalamud.Plugin.Services;
public interface IDtrBar
{
/// <summary>
/// Gets a read-only list of all DTR bar entries.
/// Gets a read-only copy of the list of all DTR bar entries.
/// </summary>
public IReadOnlyList<IReadOnlyDtrBarEntry> Entries { get; }
/// <remarks>If the list changes due to changes in order or insertion/removal, then this property will return a
/// completely new object on getter invocation. The returned object is safe to use from any thread, and will not
/// change.</remarks>
IReadOnlyList<IReadOnlyDtrBarEntry> Entries { get; }
/// <summary>
/// Get a DTR bar entry.
/// This allows you to add your own text, and users to sort it.
@ -24,11 +26,13 @@ public interface IDtrBar
/// <param name="text">The text the entry shows.</param>
/// <returns>The entry object used to update, hide and remove the entry.</returns>
/// <exception cref="ArgumentException">Thrown when an entry with the specified title exists.</exception>
public IDtrBarEntry Get(string title, SeString? text = null);
IDtrBarEntry Get(string title, SeString? text = null);
/// <summary>
/// Removes a DTR bar entry from the system.
/// </summary>
/// <param name="title">Title of the entry to remove.</param>
public void Remove(string title);
/// <remarks>Remove operation is not guaranteed to be immediately effective. Calls to <see cref="Get"/> may result
/// in an entry marked to be remove being revived and used again.</remarks>
void Remove(string title);
}