Apply most of Api10ToDo (#1782)

This commit is contained in:
srkizer 2024-04-21 15:25:33 +09:00 committed by GitHub
parent 8ff4662f1f
commit bd2c9b2258
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 115 additions and 561 deletions

View file

@ -1,6 +1,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reactive.Disposables;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dalamud.Storage; using Dalamud.Storage;
@ -20,8 +21,7 @@ public class ReliableFileStorageTests
public async Task IsConcurrencySafe() public async Task IsConcurrencySafe()
{ {
var dbDir = CreateTempDir(); var dbDir = CreateTempDir();
using var rfs = new ReliableFileStorage(dbDir); var rfs = new DisposableReliableFileStorage(dbDir);
var tempFile = Path.Combine(CreateTempDir(), TestFileName); var tempFile = Path.Combine(CreateTempDir(), TestFileName);
// Do reads/writes/deletes on the same file on many threads at once and // Do reads/writes/deletes on the same file on many threads at once and
@ -36,14 +36,14 @@ public class ReliableFileStorageTests
if (i % 2 == 0) if (i % 2 == 0)
{ {
// ReSharper disable once AccessToDisposedClosure // ReSharper disable once AccessToDisposedClosure
rfs.WriteAllText(tempFile, j.ToString()); rfs.Instance.WriteAllText(tempFile, j.ToString());
} }
else if (i % 3 == 0) else if (i % 3 == 0)
{ {
try try
{ {
// ReSharper disable once AccessToDisposedClosure // ReSharper disable once AccessToDisposedClosure
rfs.ReadAllText(tempFile); rfs.Instance.ReadAllText(tempFile);
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
@ -64,7 +64,7 @@ public class ReliableFileStorageTests
{ {
var dbDir = CreateTempDir(); var dbDir = CreateTempDir();
var dbPath = Path.Combine(dbDir, DbFileName); var dbPath = Path.Combine(dbDir, DbFileName);
using var rfs = new ReliableFileStorage(dbDir); using var rfs = new DisposableReliableFileStorage(dbDir);
Assert.True(File.Exists(dbPath)); Assert.True(File.Exists(dbPath));
} }
@ -73,14 +73,14 @@ public class ReliableFileStorageTests
public void Exists_ThrowsIfPathIsEmpty() public void Exists_ThrowsIfPathIsEmpty()
{ {
using var rfs = CreateRfs(); using var rfs = CreateRfs();
Assert.Throws<ArgumentException>(() => rfs.Exists("")); Assert.Throws<ArgumentException>(() => rfs.Instance.Exists(""));
} }
[Fact] [Fact]
public void Exists_ThrowsIfPathIsNull() public void Exists_ThrowsIfPathIsNull()
{ {
using var rfs = CreateRfs(); using var rfs = CreateRfs();
Assert.Throws<ArgumentNullException>(() => rfs.Exists(null!)); Assert.Throws<ArgumentNullException>(() => rfs.Instance.Exists(null!));
} }
[Fact] [Fact]
@ -89,7 +89,7 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName); var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateRfs(); using var rfs = CreateRfs();
Assert.False(rfs.Exists(tempFile)); Assert.False(rfs.Instance.Exists(tempFile));
} }
[Fact] [Fact]
@ -98,7 +98,7 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName); var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateFailedRfs(); using var rfs = CreateFailedRfs();
Assert.False(rfs.Exists(tempFile)); Assert.False(rfs.Instance.Exists(tempFile));
} }
[Fact] [Fact]
@ -108,7 +108,7 @@ public class ReliableFileStorageTests
await File.WriteAllTextAsync(tempFile, TestFileContent1); await File.WriteAllTextAsync(tempFile, TestFileContent1);
using var rfs = CreateRfs(); using var rfs = CreateRfs();
Assert.True(rfs.Exists(tempFile)); Assert.True(rfs.Instance.Exists(tempFile));
} }
[Fact] [Fact]
@ -117,10 +117,10 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName); var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateRfs(); using var rfs = CreateRfs();
rfs.WriteAllText(tempFile, TestFileContent1); rfs.Instance.WriteAllText(tempFile, TestFileContent1);
File.Delete(tempFile); File.Delete(tempFile);
Assert.True(rfs.Exists(tempFile)); Assert.True(rfs.Instance.Exists(tempFile));
} }
[Fact] [Fact]
@ -129,24 +129,24 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName); var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateRfs(); using var rfs = CreateRfs();
rfs.WriteAllText(tempFile, TestFileContent1); rfs.Instance.WriteAllText(tempFile, TestFileContent1);
File.Delete(tempFile); File.Delete(tempFile);
Assert.False(rfs.Exists(tempFile, Guid.NewGuid())); Assert.False(rfs.Instance.Exists(tempFile, Guid.NewGuid()));
} }
[Fact] [Fact]
public void WriteAllText_ThrowsIfPathIsEmpty() public void WriteAllText_ThrowsIfPathIsEmpty()
{ {
using var rfs = CreateRfs(); using var rfs = CreateRfs();
Assert.Throws<ArgumentException>(() => rfs.WriteAllText("", TestFileContent1)); Assert.Throws<ArgumentException>(() => rfs.Instance.WriteAllText("", TestFileContent1));
} }
[Fact] [Fact]
public void WriteAllText_ThrowsIfPathIsNull() public void WriteAllText_ThrowsIfPathIsNull()
{ {
using var rfs = CreateRfs(); using var rfs = CreateRfs();
Assert.Throws<ArgumentNullException>(() => rfs.WriteAllText(null!, TestFileContent1)); Assert.Throws<ArgumentNullException>(() => rfs.Instance.WriteAllText(null!, TestFileContent1));
} }
[Fact] [Fact]
@ -155,10 +155,10 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName); var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateRfs(); using var rfs = CreateRfs();
rfs.WriteAllText(tempFile, TestFileContent1); rfs.Instance.WriteAllText(tempFile, TestFileContent1);
Assert.True(File.Exists(tempFile)); Assert.True(File.Exists(tempFile));
Assert.Equal(TestFileContent1, rfs.ReadAllText(tempFile, forceBackup: true)); Assert.Equal(TestFileContent1, rfs.Instance.ReadAllText(tempFile, forceBackup: true));
Assert.Equal(TestFileContent1, await File.ReadAllTextAsync(tempFile)); Assert.Equal(TestFileContent1, await File.ReadAllTextAsync(tempFile));
} }
@ -169,12 +169,12 @@ public class ReliableFileStorageTests
var containerId = Guid.NewGuid(); var containerId = Guid.NewGuid();
using var rfs = CreateRfs(); using var rfs = CreateRfs();
rfs.WriteAllText(tempFile, TestFileContent1); rfs.Instance.WriteAllText(tempFile, TestFileContent1);
rfs.WriteAllText(tempFile, TestFileContent2, containerId); rfs.Instance.WriteAllText(tempFile, TestFileContent2, containerId);
File.Delete(tempFile); File.Delete(tempFile);
Assert.Equal(TestFileContent1, rfs.ReadAllText(tempFile, forceBackup: true)); Assert.Equal(TestFileContent1, rfs.Instance.ReadAllText(tempFile, forceBackup: true));
Assert.Equal(TestFileContent2, rfs.ReadAllText(tempFile, forceBackup: true, containerId)); Assert.Equal(TestFileContent2, rfs.Instance.ReadAllText(tempFile, forceBackup: true, containerId));
} }
[Fact] [Fact]
@ -183,7 +183,7 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName); var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateFailedRfs(); using var rfs = CreateFailedRfs();
rfs.WriteAllText(tempFile, TestFileContent1); rfs.Instance.WriteAllText(tempFile, TestFileContent1);
Assert.True(File.Exists(tempFile)); Assert.True(File.Exists(tempFile));
Assert.Equal(TestFileContent1, await File.ReadAllTextAsync(tempFile)); Assert.Equal(TestFileContent1, await File.ReadAllTextAsync(tempFile));
@ -195,11 +195,11 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName); var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateRfs(); using var rfs = CreateRfs();
rfs.WriteAllText(tempFile, TestFileContent1); rfs.Instance.WriteAllText(tempFile, TestFileContent1);
rfs.WriteAllText(tempFile, TestFileContent2); rfs.Instance.WriteAllText(tempFile, TestFileContent2);
Assert.True(File.Exists(tempFile)); Assert.True(File.Exists(tempFile));
Assert.Equal(TestFileContent2, rfs.ReadAllText(tempFile, forceBackup: true)); Assert.Equal(TestFileContent2, rfs.Instance.ReadAllText(tempFile, forceBackup: true));
Assert.Equal(TestFileContent2, await File.ReadAllTextAsync(tempFile)); Assert.Equal(TestFileContent2, await File.ReadAllTextAsync(tempFile));
} }
@ -209,24 +209,24 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName); var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateRfs(); using var rfs = CreateRfs();
rfs.WriteAllText(tempFile, null); rfs.Instance.WriteAllText(tempFile, null);
Assert.True(File.Exists(tempFile)); Assert.True(File.Exists(tempFile));
Assert.Equal("", rfs.ReadAllText(tempFile)); Assert.Equal("", rfs.Instance.ReadAllText(tempFile));
} }
[Fact] [Fact]
public void ReadAllText_ThrowsIfPathIsEmpty() public void ReadAllText_ThrowsIfPathIsEmpty()
{ {
using var rfs = CreateRfs(); using var rfs = CreateRfs();
Assert.Throws<ArgumentException>(() => rfs.ReadAllText("")); Assert.Throws<ArgumentException>(() => rfs.Instance.ReadAllText(""));
} }
[Fact] [Fact]
public void ReadAllText_ThrowsIfPathIsNull() public void ReadAllText_ThrowsIfPathIsNull()
{ {
using var rfs = CreateRfs(); using var rfs = CreateRfs();
Assert.Throws<ArgumentNullException>(() => rfs.ReadAllText(null!)); Assert.Throws<ArgumentNullException>(() => rfs.Instance.ReadAllText(null!));
} }
[Fact] [Fact]
@ -236,7 +236,7 @@ public class ReliableFileStorageTests
await File.WriteAllTextAsync(tempFile, TestFileContent1); await File.WriteAllTextAsync(tempFile, TestFileContent1);
using var rfs = CreateRfs(); using var rfs = CreateRfs();
Assert.Equal(TestFileContent1, rfs.ReadAllText(tempFile)); Assert.Equal(TestFileContent1, rfs.Instance.ReadAllText(tempFile));
} }
[Fact] [Fact]
@ -245,10 +245,10 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName); var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateRfs(); using var rfs = CreateRfs();
rfs.WriteAllText(tempFile, TestFileContent1); rfs.Instance.WriteAllText(tempFile, TestFileContent1);
File.Delete(tempFile); File.Delete(tempFile);
Assert.Equal(TestFileContent1, rfs.ReadAllText(tempFile)); Assert.Equal(TestFileContent1, rfs.Instance.ReadAllText(tempFile));
} }
[Fact] [Fact]
@ -258,10 +258,10 @@ public class ReliableFileStorageTests
var containerId = Guid.NewGuid(); var containerId = Guid.NewGuid();
using var rfs = CreateRfs(); using var rfs = CreateRfs();
rfs.WriteAllText(tempFile, TestFileContent1); rfs.Instance.WriteAllText(tempFile, TestFileContent1);
File.Delete(tempFile); File.Delete(tempFile);
Assert.Throws<FileNotFoundException>(() => rfs.ReadAllText(tempFile, containerId: containerId)); Assert.Throws<FileNotFoundException>(() => rfs.Instance.ReadAllText(tempFile, containerId: containerId));
} }
[Fact] [Fact]
@ -269,7 +269,7 @@ public class ReliableFileStorageTests
{ {
var tempFile = Path.Combine(CreateTempDir(), TestFileName); var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateFailedRfs(); using var rfs = CreateFailedRfs();
Assert.Throws<FileNotFoundException>(() => rfs.ReadAllText(tempFile)); Assert.Throws<FileNotFoundException>(() => rfs.Instance.ReadAllText(tempFile));
} }
[Fact] [Fact]
@ -278,7 +278,7 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName); var tempFile = Path.Combine(CreateTempDir(), TestFileName);
await File.WriteAllTextAsync(tempFile, TestFileContent1); await File.WriteAllTextAsync(tempFile, TestFileContent1);
using var rfs = CreateRfs(); using var rfs = CreateRfs();
rfs.ReadAllText(tempFile, text => Assert.Equal(TestFileContent1, text)); rfs.Instance.ReadAllText(tempFile, text => Assert.Equal(TestFileContent1, text));
} }
[Fact] [Fact]
@ -290,7 +290,7 @@ public class ReliableFileStorageTests
var readerCalledOnce = false; var readerCalledOnce = false;
using var rfs = CreateRfs(); using var rfs = CreateRfs();
Assert.Throws<FileReadException>(() => rfs.ReadAllText(tempFile, Reader)); Assert.Throws<FileReadException>(() => rfs.Instance.ReadAllText(tempFile, Reader));
return; return;
@ -311,10 +311,10 @@ public class ReliableFileStorageTests
var assertionCalled = false; var assertionCalled = false;
using var rfs = CreateRfs(); using var rfs = CreateRfs();
rfs.WriteAllText(tempFile, TestFileContent1); rfs.Instance.WriteAllText(tempFile, TestFileContent1);
File.Delete(tempFile); File.Delete(tempFile);
rfs.ReadAllText(tempFile, Reader); rfs.Instance.ReadAllText(tempFile, Reader);
Assert.True(assertionCalled); Assert.True(assertionCalled);
return; return;
@ -335,7 +335,7 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName); var tempFile = Path.Combine(CreateTempDir(), TestFileName);
await File.WriteAllTextAsync(tempFile, TestFileContent1); await File.WriteAllTextAsync(tempFile, TestFileContent1);
using var rfs = CreateRfs(); using var rfs = CreateRfs();
Assert.Throws<FileNotFoundException>(() => rfs.ReadAllText(tempFile, _ => throw new FileNotFoundException())); Assert.Throws<FileNotFoundException>(() => rfs.Instance.ReadAllText(tempFile, _ => throw new FileNotFoundException()));
} }
[Theory] [Theory]
@ -345,16 +345,16 @@ public class ReliableFileStorageTests
{ {
var tempFile = Path.Combine(CreateTempDir(), TestFileName); var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateRfs(); using var rfs = CreateRfs();
Assert.Throws<FileNotFoundException>(() => rfs.ReadAllText(tempFile, forceBackup)); Assert.Throws<FileNotFoundException>(() => rfs.Instance.ReadAllText(tempFile, forceBackup));
} }
private static ReliableFileStorage CreateRfs() private static DisposableReliableFileStorage CreateRfs()
{ {
var dbDir = CreateTempDir(); var dbDir = CreateTempDir();
return new ReliableFileStorage(dbDir); return new(dbDir);
} }
private static ReliableFileStorage CreateFailedRfs() private static DisposableReliableFileStorage CreateFailedRfs()
{ {
var dbDir = CreateTempDir(); var dbDir = CreateTempDir();
var dbPath = Path.Combine(dbDir, DbFileName); var dbPath = Path.Combine(dbDir, DbFileName);
@ -367,7 +367,7 @@ public class ReliableFileStorageTests
// Throws an SQLiteException initially, and then throws an // Throws an SQLiteException initially, and then throws an
// IOException when attempting to delete the file because // IOException when attempting to delete the file because
// there's already an active handle associated with it // there's already an active handle associated with it
return new ReliableFileStorage(dbDir); return new(dbDir);
} }
private static string CreateTempDir() private static string CreateTempDir()
@ -383,4 +383,13 @@ public class ReliableFileStorageTests
Directory.CreateDirectory(tempDir); Directory.CreateDirectory(tempDir);
return tempDir; return tempDir;
} }
private sealed class DisposableReliableFileStorage : IDisposable
{
public DisposableReliableFileStorage(string rfsDbPath) => this.Instance = new(rfsDbPath);
public ReliableFileStorage Instance { get; }
public void Dispose() => ((IInternalDisposableService)this.Instance).DisposeService();
}
} }

View file

@ -138,9 +138,7 @@ public sealed class EntryPoint
SerilogEventSink.Instance.LogLine += SerilogOnLogLine; SerilogEventSink.Instance.LogLine += SerilogOnLogLine;
// Load configuration first to get some early persistent state, like log level // Load configuration first to get some early persistent state, like log level
#pragma warning disable CS0618 // Type or member is obsolete
var fs = new ReliableFileStorage(Path.GetDirectoryName(info.ConfigurationPath)!); var fs = new ReliableFileStorage(Path.GetDirectoryName(info.ConfigurationPath)!);
#pragma warning restore CS0618 // Type or member is obsolete
var configuration = DalamudConfiguration.Load(info.ConfigurationPath!, fs); var configuration = DalamudConfiguration.Load(info.ConfigurationPath!, fs);
// Set the appropriate logging level from the configuration // Set the appropriate logging level from the configuration

View file

@ -12,9 +12,9 @@ using Dalamud.Game.Gui;
using Dalamud.Game.Text; using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.ImGuiNotification.Internal; using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal; using Dalamud.Interface.Internal;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.Internal.Windows; using Dalamud.Interface.Internal.Windows;
using Dalamud.Interface.Internal.Windows.PluginInstaller; using Dalamud.Interface.Internal.Windows.PluginInstaller;
using Dalamud.Logging.Internal; using Dalamud.Logging.Internal;

View file

@ -216,9 +216,6 @@ internal sealed partial class ObjectTable : IServiceType, IObjectTable
/// </summary> /// </summary>
internal sealed partial class ObjectTable internal sealed partial class ObjectTable
{ {
/// <inheritdoc/>
int IReadOnlyCollection<GameObject>.Count => this.Length;
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerator<GameObject> GetEnumerator() public IEnumerator<GameObject> GetEnumerator()
{ {

View file

@ -31,5 +31,5 @@ public unsafe class PlayerCharacter : BattleChara
/// <summary> /// <summary>
/// Gets the target actor ID of the PlayerCharacter. /// Gets the target actor ID of the PlayerCharacter.
/// </summary> /// </summary>
public override ulong TargetObjectId => this.Struct->Character.LookTargetId; public override ulong TargetObjectId => this.Struct->Character.Gaze.Controller.GazesSpan[0].TargetInfo.TargetId;
} }

View file

@ -1,143 +0,0 @@
using System.Numerics;
using System.Threading.Tasks;
using Dalamud.Interface.ManagedFontAtlas;
using Dalamud.Interface.ManagedFontAtlas.Internals;
using Dalamud.Utility;
using ImGuiNET;
namespace Dalamud.Interface.GameFonts;
/// <summary>
/// ABI-compatible wrapper for <see cref="IFontHandle"/>.
/// </summary>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public sealed class GameFontHandle : IFontHandle
{
private readonly GamePrebakedFontHandle fontHandle;
private readonly FontAtlasFactory fontAtlasFactory;
/// <summary>
/// Initializes a new instance of the <see cref="GameFontHandle"/> class.<br />
/// Ownership of <paramref name="fontHandle"/> is transferred.
/// </summary>
/// <param name="fontHandle">The wrapped <see cref="GamePrebakedFontHandle"/>.</param>
/// <param name="fontAtlasFactory">An instance of <see cref="FontAtlasFactory"/>.</param>
internal GameFontHandle(GamePrebakedFontHandle fontHandle, FontAtlasFactory fontAtlasFactory)
{
this.fontHandle = fontHandle;
this.fontAtlasFactory = fontAtlasFactory;
}
/// <inheritdoc />
public event IFontHandle.ImFontChangedDelegate ImFontChanged
{
add => this.fontHandle.ImFontChanged += value;
remove => this.fontHandle.ImFontChanged -= value;
}
/// <inheritdoc />
public Exception? LoadException => this.fontHandle.LoadException;
/// <inheritdoc />
public bool Available => this.fontHandle.Available;
/// <summary>
/// Gets the font.<br />
/// Use of this properly is safe only from the UI thread.<br />
/// Use <see cref="IFontHandle.Push"/> if the intended purpose of this property is <see cref="ImGui.PushFont"/>.<br />
/// Futures changes may make simple <see cref="ImGui.PushFont"/> not enough.<br />
/// If you need to access a font outside the UI thread, use <see cref="IFontHandle.Lock"/>.
/// </summary>
[Obsolete($"Use {nameof(Push)}-{nameof(ImGui.GetFont)} or {nameof(Lock)} instead.", false)]
public ImFontPtr ImFont => this.fontHandle.LockUntilPostFrame();
/// <summary>
/// Gets the font style. Only applicable for <see cref="GameFontHandle"/>.
/// </summary>
[Obsolete("If you use this, let the fact that you use this be known at Dalamud Discord.", false)]
public GameFontStyle Style => ((GamePrebakedFontHandle)this.fontHandle).FontStyle;
/// <summary>
/// Gets the relevant <see cref="FdtReader"/>.<br />
/// <br />
/// Only applicable for game fonts. Otherwise it will throw.
/// </summary>
[Obsolete("If you use this, let the fact that you use this be known at Dalamud Discord.", false)]
public FdtReader FdtReader => this.fontAtlasFactory.GetFdtReader(this.Style.FamilyAndSize)!;
/// <inheritdoc />
public void Dispose() => this.fontHandle.Dispose();
/// <inheritdoc />
public ILockedImFont Lock() => this.fontHandle.Lock();
/// <inheritdoc />
public IDisposable Push() => this.fontHandle.Push();
/// <inheritdoc />
public void Pop() => this.fontHandle.Pop();
/// <inheritdoc />
public Task<IFontHandle> WaitAsync() => this.fontHandle.WaitAsync();
/// <summary>
/// Creates a new <see cref="GameFontLayoutPlan.Builder"/>.<br />
/// <br />
/// Only applicable for game fonts. Otherwise it will throw.
/// </summary>
/// <param name="text">Text.</param>
/// <returns>A new builder for GameFontLayoutPlan.</returns>
[Obsolete("If you use this, let the fact that you use this be known at Dalamud Discord.", false)]
public GameFontLayoutPlan.Builder LayoutBuilder(string text) => new(this.ImFont, this.FdtReader, text);
/// <summary>
/// Draws text.
/// </summary>
/// <param name="text">Text to draw.</param>
[Obsolete("If you use this, let the fact that you use this be known at Dalamud Discord.", false)]
public void Text(string text)
{
if (!this.Available)
{
ImGui.TextUnformatted(text);
}
else
{
var pos = ImGui.GetWindowPos() + ImGui.GetCursorPos();
pos.X -= ImGui.GetScrollX();
pos.Y -= ImGui.GetScrollY();
var layout = this.LayoutBuilder(text).Build();
layout.Draw(ImGui.GetWindowDrawList(), pos, ImGui.GetColorU32(ImGuiCol.Text));
ImGui.Dummy(new Vector2(layout.Width, layout.Height));
}
}
/// <summary>
/// Draws text in given color.
/// </summary>
/// <param name="col">Color.</param>
/// <param name="text">Text to draw.</param>
[Obsolete("If you use this, let the fact that you use this be known at Dalamud Discord.", false)]
public void TextColored(Vector4 col, string text)
{
ImGui.PushStyleColor(ImGuiCol.Text, col);
this.Text(text);
ImGui.PopStyleColor();
}
/// <summary>
/// Draws disabled text.
/// </summary>
/// <param name="text">Text to draw.</param>
[Obsolete("If you use this, let the fact that you use this be known at Dalamud Discord.", false)]
public void TextDisabled(string text)
{
unsafe
{
this.TextColored(*ImGui.GetStyleColorVec4(ImGuiCol.TextDisabled), text);
}
}
}

View file

@ -89,30 +89,6 @@ public sealed class SingleFontChooserDialog : IDisposable
private bool popupSizeChanged; private bool popupSizeChanged;
private Vector2 popupPosition = new(float.NaN); private Vector2 popupPosition = new(float.NaN);
private Vector2 popupSize = new(float.NaN); private Vector2 popupSize = new(float.NaN);
/// <summary>Initializes a new instance of the <see cref="SingleFontChooserDialog"/> class.</summary>
/// <param name="newAsyncAtlas">A new instance of <see cref="IFontAtlas"/> created using
/// <see cref="FontAtlasAutoRebuildMode.Async"/> as its auto-rebuild mode.</param>
/// <remarks>The passed instance of <paramref see="newAsyncAtlas"/> will be disposed after use. If you pass an atlas
/// that is already being used, then all the font handles under the passed atlas will be invalidated upon disposing
/// this font chooser. Consider using <see cref="SingleFontChooserDialog(UiBuilder, bool, string?)"/> for automatic
/// handling of font atlas derived from a <see cref="UiBuilder"/>, or even <see cref="CreateAuto"/> for automatic
/// registration and unregistration of <see cref="Draw"/> event handler in addition to automatic disposal of this
/// class and the temporary font atlas for this font chooser dialog.</remarks>
[Obsolete("See remarks, and use the other constructor.", false)]
[Api10ToDo("Make private.")]
public SingleFontChooserDialog(IFontAtlas newAsyncAtlas)
{
this.counter = Interlocked.Increment(ref counterStatic);
this.title = "Choose a font...";
this.popupImGuiName = $"{this.title}##{nameof(SingleFontChooserDialog)}[{this.counter}]";
this.atlas = newAsyncAtlas;
this.selectedFont = new() { FontId = DalamudDefaultFontAndFamilyId.Instance };
Encoding.UTF8.GetBytes("Font preview.\n0123456789!", this.fontPreviewText);
}
#pragma warning disable CS0618 // Type or member is obsolete
// TODO: Api10ToDo; Remove this pragma warning disable line
/// <summary>Initializes a new instance of the <see cref="SingleFontChooserDialog"/> class.</summary> /// <summary>Initializes a new instance of the <see cref="SingleFontChooserDialog"/> class.</summary>
/// <param name="uiBuilder">The relevant instance of UiBuilder.</param> /// <param name="uiBuilder">The relevant instance of UiBuilder.</param>
@ -137,9 +113,25 @@ public sealed class SingleFontChooserDialog : IDisposable
: this(factory.CreateFontAtlas(debugAtlasName, FontAtlasAutoRebuildMode.Async)) : this(factory.CreateFontAtlas(debugAtlasName, FontAtlasAutoRebuildMode.Async))
{ {
} }
#pragma warning restore CS0618 // Type or member is obsolete /// <summary>Initializes a new instance of the <see cref="SingleFontChooserDialog"/> class.</summary>
// TODO: Api10ToDo; Remove this pragma warning restore line /// <param name="newAsyncAtlas">A new instance of <see cref="IFontAtlas"/> created using
/// <see cref="FontAtlasAutoRebuildMode.Async"/> as its auto-rebuild mode.</param>
/// <remarks>The passed instance of <paramref see="newAsyncAtlas"/> will be disposed after use. If you pass an atlas
/// that is already being used, then all the font handles under the passed atlas will be invalidated upon disposing
/// this font chooser. Consider using <see cref="SingleFontChooserDialog(UiBuilder, bool, string?)"/> for automatic
/// handling of font atlas derived from a <see cref="UiBuilder"/>, or even <see cref="CreateAuto"/> for automatic
/// registration and unregistration of <see cref="Draw"/> event handler in addition to automatic disposal of this
/// class and the temporary font atlas for this font chooser dialog.</remarks>
private SingleFontChooserDialog(IFontAtlas newAsyncAtlas)
{
this.counter = Interlocked.Increment(ref counterStatic);
this.title = "Choose a font...";
this.popupImGuiName = $"{this.title}##{nameof(SingleFontChooserDialog)}[{this.counter}]";
this.atlas = newAsyncAtlas;
this.selectedFont = new() { FontId = DalamudDefaultFontAndFamilyId.Instance };
Encoding.UTF8.GetBytes("Font preview.\n0123456789!", this.fontPreviewText);
}
/// <summary>Called when the selected font spec has changed.</summary> /// <summary>Called when the selected font spec has changed.</summary>
public event Action<SingleFontSpec>? SelectedFontSpecChanged; public event Action<SingleFontSpec>? SelectedFontSpecChanged;

View file

@ -1,7 +1,6 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Dalamud.Interface.Internal; using Dalamud.Interface.Internal;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
namespace Dalamud.Interface.ImGuiNotification; namespace Dalamud.Interface.ImGuiNotification;

View file

@ -5,7 +5,6 @@ using Dalamud.Configuration.Internal;
using Dalamud.Interface.Animation; using Dalamud.Interface.Animation;
using Dalamud.Interface.Animation.EasingFunctions; using Dalamud.Interface.Animation.EasingFunctions;
using Dalamud.Interface.Internal; using Dalamud.Interface.Internal;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Plugin.Internal.Types; using Dalamud.Plugin.Internal.Types;
using Dalamud.Utility; using Dalamud.Utility;

View file

@ -3,7 +3,6 @@ using System.Numerics;
using CheapLoc; using CheapLoc;
using Dalamud.Interface.Colors; using Dalamud.Interface.Colors;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
namespace Dalamud.Interface.ImGuiNotification.Internal; namespace Dalamud.Interface.ImGuiNotification.Internal;

View file

@ -3,7 +3,6 @@ using System.Collections.Generic;
using Dalamud.Game.Gui; using Dalamud.Game.Gui;
using Dalamud.Interface.GameFonts; using Dalamud.Interface.GameFonts;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.ManagedFontAtlas; using Dalamud.Interface.ManagedFontAtlas;
using Dalamud.Interface.ManagedFontAtlas.Internals; using Dalamud.Interface.ManagedFontAtlas.Internals;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;

View file

@ -2,7 +2,6 @@ using System.Threading.Tasks;
using Dalamud.Interface.ImGuiNotification.Internal; using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal; using Dalamud.Interface.Internal;
using Dalamud.Interface.Internal.Notifications;
namespace Dalamud.Interface.ImGuiNotification; namespace Dalamud.Interface.ImGuiNotification;

View file

@ -1,9 +1,6 @@
using Dalamud.Utility; namespace Dalamud.Interface.ImGuiNotification;
namespace Dalamud.Interface.Internal.Notifications;
/// <summary>Possible notification types.</summary> /// <summary>Possible notification types.</summary>
[Api10ToDo(Api10ToDoAttribute.MoveNamespace, nameof(ImGuiNotification.Internal))]
public enum NotificationType public enum NotificationType
{ {
/// <summary>No special type.</summary> /// <summary>No special type.</summary>

View file

@ -14,7 +14,6 @@ using Dalamud.Interface.Colors;
using Dalamud.Interface.Components; using Dalamud.Interface.Components;
using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.ImGuiNotification.Internal; using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;

View file

@ -5,8 +5,8 @@ using System.Numerics;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.ImGuiNotification.Internal; using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Utility.Raii;
using Dalamud.Plugin.Ipc.Internal; using Dalamud.Plugin.Ipc.Internal;

View file

@ -5,7 +5,6 @@ using System.Threading.Tasks;
using Dalamud.Game.Text; using Dalamud.Game.Text;
using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.ImGuiNotification.Internal; using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using Dalamud.Storage.Assets; using Dalamud.Storage.Assets;
using Dalamud.Utility; using Dalamud.Utility;

View file

@ -15,8 +15,8 @@ using Dalamud.Game.Command;
using Dalamud.Interface.Animation.EasingFunctions; using Dalamud.Interface.Animation.EasingFunctions;
using Dalamud.Interface.Colors; using Dalamud.Interface.Colors;
using Dalamud.Interface.Components; using Dalamud.Interface.Components;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.ImGuiNotification.Internal; using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;

View file

@ -7,8 +7,8 @@ using CheapLoc;
using Dalamud.Configuration.Internal; using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors; using Dalamud.Interface.Colors;
using Dalamud.Interface.Components; using Dalamud.Interface.Components;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.ImGuiNotification.Internal; using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Utility.Raii;
using Dalamud.Plugin.Internal; using Dalamud.Plugin.Internal;

View file

@ -7,8 +7,8 @@ using System.Reflection;
using Dalamud.Game; using Dalamud.Game;
using Dalamud.Hooking.Internal; using Dalamud.Hooking.Internal;
using Dalamud.Interface.Components; using Dalamud.Interface.Components;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.ImGuiNotification.Internal; using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using Dalamud.Plugin.Internal; using Dalamud.Plugin.Internal;
using Dalamud.Plugin.Internal.Types; using Dalamud.Plugin.Internal.Types;

View file

@ -85,10 +85,9 @@ public interface IFontAtlas : IDisposable
/// <summary>Creates a new <see cref="IFontHandle"/> from game's built-in fonts.</summary> /// <summary>Creates a new <see cref="IFontHandle"/> from game's built-in fonts.</summary>
/// <param name="style">Font to use.</param> /// <param name="style">Font to use.</param>
/// <returns>Handle to a font that may or may not be ready yet.</returns> /// <returns>Handle to a font that may or may not be ready yet.</returns>
/// <exception cref="InvalidOperationException">When called during <see cref="BuildStepChange"/>, /// <exception cref="InvalidOperationException">When called during <see cref="BuildStepChange"/> and alike.
/// <see cref="UiBuilder.BuildFonts"/>, <see cref="UiBuilder.AfterBuildFonts"/>, and alike. Move the font handle /// Move the font handle creating code outside those handlers, and only initialize them once.
/// creating code outside those handlers, and only initialize them once. Call <see cref="IDisposable.Dispose"/> /// Call <see cref="IDisposable.Dispose"/> on a previous font handle if you're replacing one.</exception>
/// on a previous font handle if you're replacing one.</exception>
/// <remarks>This function does not throw. <see cref="IFontHandle.LoadException"/> will be populated instead, if /// <remarks>This function does not throw. <see cref="IFontHandle.LoadException"/> will be populated instead, if
/// the build procedure has failed. <see cref="IFontHandle.Push"/> can be used regardless of the state of the font /// the build procedure has failed. <see cref="IFontHandle.Push"/> can be used regardless of the state of the font
/// handle.</remarks> /// handle.</remarks>
@ -97,10 +96,9 @@ public interface IFontAtlas : IDisposable
/// <summary>Creates a new IFontHandle using your own callbacks.</summary> /// <summary>Creates a new IFontHandle using your own callbacks.</summary>
/// <param name="buildStepDelegate">Callback for <see cref="IFontAtlas.BuildStepChange"/>.</param> /// <param name="buildStepDelegate">Callback for <see cref="IFontAtlas.BuildStepChange"/>.</param>
/// <returns>Handle to a font that may or may not be ready yet.</returns> /// <returns>Handle to a font that may or may not be ready yet.</returns>
/// <exception cref="InvalidOperationException">When called during <see cref="BuildStepChange"/>, /// <exception cref="InvalidOperationException">When called during <see cref="BuildStepChange"/> and alike.
/// <see cref="UiBuilder.BuildFonts"/>, <see cref="UiBuilder.AfterBuildFonts"/>, and alike. Move the font handle /// Move the font handle creating code outside those handlers, and only initialize them once.
/// creating code outside those handlers, and only initialize them once. Call <see cref="IDisposable.Dispose"/> /// Call <see cref="IDisposable.Dispose"/> on a previous font handle if you're replacing one.</exception>
/// on a previous font handle if you're replacing one.</exception>
/// <remarks>Consider calling <see cref="IFontAtlasBuildToolkitPreBuild.AttachExtraGlyphsForDalamudLanguage"/> to /// <remarks>Consider calling <see cref="IFontAtlasBuildToolkitPreBuild.AttachExtraGlyphsForDalamudLanguage"/> to
/// support glyphs that are not supplied by the game by default; this mostly affects Chinese and Korean language /// support glyphs that are not supplied by the game by default; this mostly affects Chinese and Korean language
/// users.</remarks> /// users.</remarks>

View file

@ -1,8 +1,6 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Dalamud.Interface.ManagedFontAtlas.Internals;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
using Dalamud.Utility;
using ImGuiNET; using ImGuiNET;
@ -14,20 +12,6 @@ namespace Dalamud.Interface.ManagedFontAtlas;
/// </summary> /// </summary>
public interface IFontAtlasBuildToolkit public interface IFontAtlasBuildToolkit
{ {
/// <summary>
/// Functionalities for compatibility behavior.<br />
/// </summary>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
internal interface IApi9Compat : IFontAtlasBuildToolkit
{
/// <summary>
/// Invokes <paramref name="action"/>, temporarily applying <see cref="IFontHandleSubstance"/>s.<br />
/// </summary>
/// <param name="action">The action to invoke.</param>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public void FromUiBuilderObsoleteEventHandlers(Action action);
}
/// <summary> /// <summary>
/// Gets or sets the font relevant to the call. /// Gets or sets the font relevant to the call.
/// </summary> /// </summary>

View file

@ -1,5 +1,4 @@
using Dalamud.Interface.Internal; using Dalamud.Interface.Internal;
using Dalamud.Utility;
using ImGuiNET; using ImGuiNET;
@ -11,11 +10,6 @@ namespace Dalamud.Interface.ManagedFontAtlas;
/// </summary> /// </summary>
public interface IFontAtlasBuildToolkitPostBuild : IFontAtlasBuildToolkit public interface IFontAtlasBuildToolkitPostBuild : IFontAtlasBuildToolkit
{ {
/// <inheritdoc cref="IFontAtlasBuildToolkitPreBuild.IsGlobalScaleIgnored"/>
[Obsolete($"Use {nameof(this.GetFontScaleMode)}")]
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
bool IsGlobalScaleIgnored(ImFontPtr fontPtr) => this.GetFontScaleMode(fontPtr) == FontScaleMode.UndoGlobalScale;
/// <inheritdoc cref="IFontAtlasBuildToolkitPreBuild.GetFontScaleMode"/> /// <inheritdoc cref="IFontAtlasBuildToolkitPreBuild.GetFontScaleMode"/>
FontScaleMode GetFontScaleMode(ImFontPtr fontPtr); FontScaleMode GetFontScaleMode(ImFontPtr fontPtr);

View file

@ -44,25 +44,6 @@ public interface IFontAtlasBuildToolkitPreBuild : IFontAtlasBuildToolkit
/// <param name="action">The action to run on dispose.</param> /// <param name="action">The action to run on dispose.</param>
void DisposeAfterBuild(Action action); void DisposeAfterBuild(Action action);
/// <summary>
/// Excludes given font from global scaling.
/// </summary>
/// <param name="fontPtr">The font.</param>
/// <returns>Same <see cref="ImFontPtr"/> with <paramref name="fontPtr"/>.</returns>
[Obsolete(
$"Use {nameof(this.SetFontScaleMode)} with {nameof(FontScaleMode)}.{nameof(FontScaleMode.UndoGlobalScale)}")]
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
ImFontPtr IgnoreGlobalScale(ImFontPtr fontPtr) => this.SetFontScaleMode(fontPtr, FontScaleMode.UndoGlobalScale);
/// <summary>
/// Gets whether global scaling is ignored for the given font.
/// </summary>
/// <param name="fontPtr">The font.</param>
/// <returns>True if ignored.</returns>
[Obsolete($"Use {nameof(this.GetFontScaleMode)}")]
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
bool IsGlobalScaleIgnored(ImFontPtr fontPtr) => this.GetFontScaleMode(fontPtr) == FontScaleMode.UndoGlobalScale;
/// <summary> /// <summary>
/// Sets the scaling mode for the given font. /// Sets the scaling mode for the given font.
/// </summary> /// </summary>

View file

@ -132,14 +132,6 @@ internal sealed class DelegateFontHandle : FontHandle
/// <inheritdoc/> /// <inheritdoc/>
public IFontHandleManager Manager { get; } public IFontHandleManager Manager { get; }
/// <inheritdoc/>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public IFontAtlasBuildToolkitPreBuild? PreBuildToolkitForApi9Compat { get; set; }
/// <inheritdoc/>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public bool CreateFontOnAccess { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public void Dispose() public void Dispose()
{ {

View file

@ -33,7 +33,7 @@ internal sealed partial class FontAtlasFactory
/// Implementations for <see cref="IFontAtlasBuildToolkitPreBuild"/> and /// Implementations for <see cref="IFontAtlasBuildToolkitPreBuild"/> and
/// <see cref="IFontAtlasBuildToolkitPostBuild"/>. /// <see cref="IFontAtlasBuildToolkitPostBuild"/>.
/// </summary> /// </summary>
private class BuildToolkit : IFontAtlasBuildToolkit.IApi9Compat, IFontAtlasBuildToolkitPreBuild, IFontAtlasBuildToolkitPostBuild, IDisposable private class BuildToolkit : IFontAtlasBuildToolkitPreBuild, IFontAtlasBuildToolkitPostBuild, IDisposable
{ {
private static readonly ushort FontAwesomeIconMin = private static readonly ushort FontAwesomeIconMin =
(ushort)Enum.GetValues<FontAwesomeIcon>().Where(x => x > 0).Min(); (ushort)Enum.GetValues<FontAwesomeIcon>().Where(x => x > 0).Min();
@ -111,34 +111,6 @@ internal sealed partial class FontAtlasFactory
/// <inheritdoc/> /// <inheritdoc/>
public void DisposeWithAtlas(Action action) => this.data.Garbage.Add(action); public void DisposeWithAtlas(Action action) => this.data.Garbage.Add(action);
/// <inheritdoc/>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public void FromUiBuilderObsoleteEventHandlers(Action action)
{
var previousSubstances = new IFontHandleSubstance[this.data.Substances.Count];
for (var i = 0; i < previousSubstances.Length; i++)
{
previousSubstances[i] = this.data.Substances[i].Manager.Substance;
this.data.Substances[i].Manager.Substance = this.data.Substances[i];
this.data.Substances[i].CreateFontOnAccess = true;
this.data.Substances[i].PreBuildToolkitForApi9Compat = this;
}
try
{
action();
}
finally
{
for (var i = 0; i < previousSubstances.Length; i++)
{
this.data.Substances[i].Manager.Substance = previousSubstances[i];
this.data.Substances[i].CreateFontOnAccess = false;
this.data.Substances[i].PreBuildToolkitForApi9Compat = null;
}
}
}
/// <inheritdoc/> /// <inheritdoc/>
public ImFontPtr GetFont(IFontHandle fontHandle) public ImFontPtr GetFont(IFontHandle fontHandle)
{ {

View file

@ -435,7 +435,7 @@ internal sealed partial class FontAtlasFactory
if (IsBuildInProgressForTask.Value) if (IsBuildInProgressForTask.Value)
{ {
throw new InvalidOperationException( throw new InvalidOperationException(
$"{nameof(this.NewGameFontHandle)} may not be called during {nameof(this.BuildStepChange)}, the callback of {nameof(this.NewDelegateFontHandle)}, {nameof(UiBuilder.BuildFonts)} or {nameof(UiBuilder.AfterBuildFonts)}."); $"{nameof(this.NewGameFontHandle)} may not be called during {nameof(this.BuildStepChange)} or the callback of {nameof(this.NewDelegateFontHandle)}.");
} }
return this.gameFontHandleManager.NewFontHandle(style); return this.gameFontHandleManager.NewFontHandle(style);
@ -447,7 +447,7 @@ internal sealed partial class FontAtlasFactory
if (IsBuildInProgressForTask.Value) if (IsBuildInProgressForTask.Value)
{ {
throw new InvalidOperationException( throw new InvalidOperationException(
$"{nameof(this.NewDelegateFontHandle)} may not be called during {nameof(this.BuildStepChange)} or the callback of {nameof(this.NewDelegateFontHandle)}, {nameof(UiBuilder.BuildFonts)} or {nameof(UiBuilder.AfterBuildFonts)}."); $"{nameof(this.NewDelegateFontHandle)} may not be called during {nameof(this.BuildStepChange)} or the callback of {nameof(this.NewDelegateFontHandle)}.");
} }
return this.delegateFontHandleManager.NewFontHandle(buildStepDelegate); return this.delegateFontHandleManager.NewFontHandle(buildStepDelegate);

View file

@ -231,14 +231,6 @@ internal class GamePrebakedFontHandle : FontHandle
/// <inheritdoc/> /// <inheritdoc/>
public IFontHandleManager Manager => this.handleManager; public IFontHandleManager Manager => this.handleManager;
/// <inheritdoc/>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public IFontAtlasBuildToolkitPreBuild? PreBuildToolkitForApi9Compat { get; set; }
/// <inheritdoc/>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public bool CreateFontOnAccess { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public void Dispose() public void Dispose()
{ {
@ -295,27 +287,11 @@ internal class GamePrebakedFontHandle : FontHandle
} }
} }
// Use this on API 10.
// /// <inheritdoc/>
// public ImFontPtr GetFontPtr(IFontHandle handle) =>
// handle is GamePrebakedFontHandle ggfh
// ? this.fonts.GetValueOrDefault(ggfh.FontStyle)?.FullRangeFont ?? default
// : default;
/// <inheritdoc/> /// <inheritdoc/>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)] public ImFontPtr GetFontPtr(IFontHandle handle) =>
public ImFontPtr GetFontPtr(IFontHandle handle) handle is GamePrebakedFontHandle ggfh
{ ? this.fonts.GetValueOrDefault(ggfh.FontStyle)?.FullRangeFont ?? default
if (handle is not GamePrebakedFontHandle ggfh) : default;
return default;
if (this.fonts.GetValueOrDefault(ggfh.FontStyle)?.FullRangeFont is { } font)
return font;
if (!this.CreateFontOnAccess)
return default;
if (this.PreBuildToolkitForApi9Compat is not { } tk)
return default;
return this.GetOrCreateFont(ggfh.FontStyle, tk);
}
/// <inheritdoc/> /// <inheritdoc/>
public Exception? GetBuildException(IFontHandle handle) => public Exception? GetBuildException(IFontHandle handle) =>

View file

@ -21,19 +21,6 @@ internal interface IFontHandleSubstance : IDisposable
/// </summary> /// </summary>
IFontHandleManager Manager { get; } IFontHandleManager Manager { get; }
/// <summary>
/// Gets or sets the relevant <see cref="IFontAtlasBuildToolkitPreBuild"/> for this.
/// </summary>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
IFontAtlasBuildToolkitPreBuild? PreBuildToolkitForApi9Compat { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to create a new instance of <see cref="ImGuiNET.ImFontPtr"/> on first
/// access, for compatibility with API 9.
/// </summary>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
bool CreateFontOnAccess { get; set; }
/// <summary> /// <summary>
/// Gets the relevant handles. /// Gets the relevant handles.
/// </summary> /// </summary>

View file

@ -1,4 +1,3 @@
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -9,17 +8,10 @@ using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.Gui; using Dalamud.Game.Gui;
using Dalamud.Interface.FontIdentifier; using Dalamud.Interface.FontIdentifier;
using Dalamud.Interface.GameFonts;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal; using Dalamud.Interface.Internal;
using Dalamud.Interface.Internal.ManagedAsserts; using Dalamud.Interface.Internal.ManagedAsserts;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.ManagedFontAtlas; using Dalamud.Interface.ManagedFontAtlas;
using Dalamud.Interface.ManagedFontAtlas.Internals; using Dalamud.Interface.ManagedFontAtlas.Internals;
using Dalamud.Plugin;
using Dalamud.Plugin.Internal.Types;
using Dalamud.Plugin.Services;
using Dalamud.Utility; using Dalamud.Utility;
using ImGuiNET; using ImGuiNET;
@ -38,13 +30,11 @@ namespace Dalamud.Interface;
/// </summary> /// </summary>
public sealed class UiBuilder : IDisposable public sealed class UiBuilder : IDisposable
{ {
private readonly LocalPlugin localPlugin;
private readonly Stopwatch stopwatch; private readonly Stopwatch stopwatch;
private readonly HitchDetector hitchDetector; private readonly HitchDetector hitchDetector;
private readonly string namespaceName; private readonly string namespaceName;
private readonly InterfaceManager interfaceManager = Service<InterfaceManager>.Get(); private readonly InterfaceManager interfaceManager = Service<InterfaceManager>.Get();
private readonly Framework framework = Service<Framework>.Get(); private readonly Framework framework = Service<Framework>.Get();
private readonly ConcurrentDictionary<IActiveNotification, int> notifications = new();
[ServiceManager.ServiceDependency] [ServiceManager.ServiceDependency]
private readonly DalamudConfiguration configuration = Service<DalamudConfiguration>.Get(); private readonly DalamudConfiguration configuration = Service<DalamudConfiguration>.Get();
@ -64,10 +54,8 @@ public sealed class UiBuilder : IDisposable
/// You do not have to call this manually. /// You do not have to call this manually.
/// </summary> /// </summary>
/// <param name="namespaceName">The plugin namespace.</param> /// <param name="namespaceName">The plugin namespace.</param>
/// <param name="localPlugin">The relevant local plugin.</param> internal UiBuilder(string namespaceName)
internal UiBuilder(string namespaceName, LocalPlugin localPlugin)
{ {
this.localPlugin = localPlugin;
try try
{ {
this.stopwatch = new Stopwatch(); this.stopwatch = new Stopwatch();
@ -85,9 +73,7 @@ public sealed class UiBuilder : IDisposable
.Add( .Add(
Service<FontAtlasFactory> Service<FontAtlasFactory>
.Get() .Get()
.CreateFontAtlas(namespaceName, FontAtlasAutoRebuildMode.Disable)); .CreateFontAtlas(namespaceName, FontAtlasAutoRebuildMode.Async));
this.FontAtlas.BuildStepChange += this.PrivateAtlasOnBuildStepChange;
this.FontAtlas.RebuildRecommend += this.RebuildFonts;
} }
catch catch
{ {
@ -100,90 +86,34 @@ public sealed class UiBuilder : IDisposable
/// The event that gets called when Dalamud is ready to draw your windows or overlays. /// The event that gets called when Dalamud is ready to draw your windows or overlays.
/// When it is called, you can use static ImGui calls. /// When it is called, you can use static ImGui calls.
/// </summary> /// </summary>
public event Action Draw; public event Action? Draw;
/// <summary> /// <summary>
/// The event that is called when the game's DirectX device is requesting you to resize your buffers. /// The event that is called when the game's DirectX device is requesting you to resize your buffers.
/// </summary> /// </summary>
public event Action ResizeBuffers; public event Action? ResizeBuffers;
/// <summary> /// <summary>
/// Event that is fired when the plugin should open its configuration interface. /// Event that is fired when the plugin should open its configuration interface.
/// </summary> /// </summary>
public event Action OpenConfigUi; public event Action? OpenConfigUi;
/// <summary> /// <summary>
/// Event that is fired when the plugin should open its main interface. /// Event that is fired when the plugin should open its main interface.
/// </summary> /// </summary>
public event Action OpenMainUi; public event Action? OpenMainUi;
/// <summary>
/// Gets or sets an action that is called any time ImGui fonts need to be rebuilt.<br/>
/// Any ImFontPtr objects that you store <b>can be invalidated</b> when fonts are rebuilt
/// (at any time), so you should both reload your custom fonts and restore those
/// pointers inside this handler.
/// </summary>
/// <remarks>
/// To add your custom font, use <see cref="FontAtlas"/>.<see cref="IFontAtlas.NewDelegateFontHandle"/> or
/// <see cref="IFontAtlas.NewGameFontHandle"/>.<br />
/// To be notified on font changes after fonts are built, use
/// <see cref="DefaultFontHandle"/>.<see cref="IFontHandle.ImFontChanged"/>.<br />
/// For all other purposes, use <see cref="FontAtlas"/>.<see cref="IFontAtlas.BuildStepChange"/>.<br />
/// <br />
/// Note that you will be calling above functions once, instead of every time inside a build step change callback.
/// For example, you can make all font handles from your plugin constructor, and then use the created handles during
/// <see cref="Draw"/> event, by using <see cref="IFontHandle.Push"/> in a scope.<br />
/// You may dispose your font handle anytime, as long as it's not in use in <see cref="Draw"/>.
/// Font handles may be constructed anytime, as long as the owner <see cref="IFontAtlas"/> or
/// <see cref="UiBuilder"/> is not disposed.<br />
/// <br />
/// If you were storing <see cref="ImFontPtr"/>, consider if the job can be achieved solely by using
/// <see cref="IFontHandle"/> without directly using an instance of <see cref="ImFontPtr"/>.<br />
/// If you do need it, evaluate if you need to access fonts outside the main thread.<br />
/// If it is the case, use <see cref="IFontHandle.Lock"/> to obtain a safe-to-access instance of
/// <see cref="ImFontPtr"/>, once <see cref="IFontHandle.WaitAsync"/> resolves.<br />
/// Otherwise, use <see cref="IFontHandle.Push"/>, and obtain the instance of <see cref="ImFontPtr"/> via
/// <see cref="ImGui.GetFont"/>. Do not let the <see cref="ImFontPtr"/> escape the <c>using</c> scope.<br />
/// <br />
/// If your plugin sets <see cref="PluginManifest.LoadRequiredState"/> to a non-default value, then
/// <see cref="DefaultFontHandle"/> should be accessed using
/// <see cref="RunWhenUiPrepared{T}(System.Func{T},bool)"/>, as the font handle member variables are only available
/// once drawing facilities are available.<br />
/// <br />
/// <b>Examples:</b><br />
/// * <see cref="InterfaceManager.ContinueConstruction"/>.<br />
/// * <see cref="Interface.Internal.Windows.Data.Widgets.GamePrebakedFontsTestWidget"/>.<br />
/// * <see cref="Interface.Internal.Windows.TitleScreenMenuWindow"/> ctor.<br />
/// * <see cref="Interface.Internal.Windows.Settings.Tabs.SettingsTabAbout"/>:
/// note how the construction of a new instance of <see cref="IFontAtlas"/> and
/// call of <see cref="IFontAtlas.NewGameFontHandle"/> are done in different functions,
/// without having to manually initiate font rebuild process.
/// </remarks>
[Obsolete("See remarks.", false)]
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public event Action? BuildFonts;
/// <summary>
/// Gets or sets an action that is called any time right after ImGui fonts are rebuilt.<br/>
/// Any ImFontPtr objects that you store <b>can be invalidated</b> when fonts are rebuilt
/// (at any time), so you should both reload your custom fonts and restore those
/// pointers inside this handler.
/// </summary>
[Obsolete($"See remarks for {nameof(BuildFonts)}.", false)]
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public event Action? AfterBuildFonts;
/// <summary> /// <summary>
/// Gets or sets an action that is called when plugin UI or interface modifications are supposed to be shown. /// Gets or sets an action that is called when plugin UI or interface modifications are supposed to be shown.
/// These may be fired consecutively. /// These may be fired consecutively.
/// </summary> /// </summary>
public event Action ShowUi; public event Action? ShowUi;
/// <summary> /// <summary>
/// Gets or sets an action that is called when plugin UI or interface modifications are supposed to be hidden. /// Gets or sets an action that is called when plugin UI or interface modifications are supposed to be hidden.
/// These may be fired consecutively. /// These may be fired consecutively.
/// </summary> /// </summary>
public event Action HideUi; public event Action? HideUi;
/// <summary> /// <summary>
/// Gets the default Dalamud font size in points. /// Gets the default Dalamud font size in points.
@ -291,12 +221,12 @@ public sealed class UiBuilder : IDisposable
/// <summary> /// <summary>
/// Gets the game's active Direct3D device. /// Gets the game's active Direct3D device.
/// </summary> /// </summary>
public Device Device => this.InterfaceManagerWithScene.Device!; public Device Device => this.InterfaceManagerWithScene!.Device!;
/// <summary> /// <summary>
/// Gets the game's main window handle. /// Gets the game's main window handle.
/// </summary> /// </summary>
public IntPtr WindowHandlePtr => this.InterfaceManagerWithScene.WindowHandlePtr; public IntPtr WindowHandlePtr => this.InterfaceManagerWithScene!.WindowHandlePtr;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether this plugin should hide its UI automatically when the game's UI is hidden. /// Gets or sets a value indicating whether this plugin should hide its UI automatically when the game's UI is hidden.
@ -530,38 +460,6 @@ public sealed class UiBuilder : IDisposable
} }
} }
/// <summary>
/// Gets a game font.
/// </summary>
/// <param name="style">Font to get.</param>
/// <returns>Handle to the game font which may or may not be available for use yet.</returns>
[Obsolete($"Use {nameof(this.FontAtlas)}.{nameof(IFontAtlas.NewGameFontHandle)} instead.", false)]
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public GameFontHandle GetGameFontHandle(GameFontStyle style)
{
var prevValue = FontAtlasFactory.IsBuildInProgressForTask.Value;
FontAtlasFactory.IsBuildInProgressForTask.Value = false;
var v = new GameFontHandle(
(GamePrebakedFontHandle)this.FontAtlas.NewGameFontHandle(style),
Service<FontAtlasFactory>.Get());
FontAtlasFactory.IsBuildInProgressForTask.Value = prevValue;
return v;
}
/// <summary>
/// Call this to queue a rebuild of the font atlas.<br/>
/// This will invoke any <see cref="BuildFonts"/> and <see cref="AfterBuildFonts"/> handlers and ensure that any
/// loaded fonts are ready to be used on the next UI frame.
/// </summary>
public void RebuildFonts()
{
Log.Verbose("[FONT] {0} plugin is initiating FONT REBUILD", this.namespaceName);
if (this.AfterBuildFonts is null && this.BuildFonts is null)
this.FontAtlas.BuildFontsAsync();
else
this.FontAtlas.BuildFontsOnNextFrame();
}
/// <summary> /// <summary>
/// Creates an isolated <see cref="IFontAtlas"/>. /// Creates an isolated <see cref="IFontAtlas"/>.
/// </summary> /// </summary>
@ -635,16 +533,15 @@ public sealed class UiBuilder : IDisposable
this.hitchDetector.Start(); this.hitchDetector.Start();
var clientState = Service<ClientState>.Get(); var clientState = Service<ClientState>.Get();
var configuration = Service<DalamudConfiguration>.Get();
var gameGui = Service<GameGui>.GetNullable(); var gameGui = Service<GameGui>.GetNullable();
if (gameGui == null) if (gameGui == null)
return; return;
if ((gameGui.GameUiHidden && configuration.ToggleUiHide && if ((gameGui.GameUiHidden && this.configuration.ToggleUiHide &&
!(this.DisableUserUiHide || this.DisableAutomaticUiHide)) || !(this.DisableUserUiHide || this.DisableAutomaticUiHide)) ||
(this.CutsceneActive && configuration.ToggleUiHideDuringCutscenes && (this.CutsceneActive && this.configuration.ToggleUiHideDuringCutscenes &&
!(this.DisableCutsceneUiHide || this.DisableAutomaticUiHide)) || !(this.DisableCutsceneUiHide || this.DisableAutomaticUiHide)) ||
(clientState.IsGPosing && configuration.ToggleUiHideDuringGpose && (clientState.IsGPosing && this.configuration.ToggleUiHideDuringGpose &&
!(this.DisableGposeUiHide || this.DisableAutomaticUiHide))) !(this.DisableGposeUiHide || this.DisableAutomaticUiHide)))
{ {
if (!this.lastFrameUiHideState) if (!this.lastFrameUiHideState)
@ -663,11 +560,8 @@ public sealed class UiBuilder : IDisposable
} }
// just in case, if something goes wrong, prevent drawing; otherwise it probably will crash. // just in case, if something goes wrong, prevent drawing; otherwise it probably will crash.
if (!this.FontAtlas.BuildTask.IsCompletedSuccessfully if (!this.FontAtlas.BuildTask.IsCompletedSuccessfully)
&& (this.BuildFonts is not null || this.AfterBuildFonts is not null))
{
return; return;
}
ImGui.PushID(this.namespaceName); ImGui.PushID(this.namespaceName);
if (DoStats) if (DoStats)
@ -688,11 +582,7 @@ public sealed class UiBuilder : IDisposable
ImGui.End(); ImGui.End();
} }
ImGuiManagedAsserts.ImGuiContextSnapshot snapshot = null; var snapshot = this.Draw is null ? null : ImGuiManagedAsserts.GetSnapshot();
if (this.Draw != null)
{
snapshot = ImGuiManagedAsserts.GetSnapshot();
}
try try
{ {
@ -708,10 +598,8 @@ public sealed class UiBuilder : IDisposable
} }
// Only if Draw was successful // Only if Draw was successful
if (this.Draw != null) if (this.Draw is not null && snapshot is not null)
{
ImGuiManagedAsserts.ReportProblems(this.namespaceName, snapshot); ImGuiManagedAsserts.ReportProblems(this.namespaceName, snapshot);
}
this.FrameCount++; this.FrameCount++;
@ -729,41 +617,6 @@ public sealed class UiBuilder : IDisposable
this.hitchDetector.Stop(); this.hitchDetector.Stop();
} }
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
private unsafe void PrivateAtlasOnBuildStepChange(IFontAtlasBuildToolkit e)
{
if (e.IsAsyncBuildOperation)
return;
ThreadSafety.AssertMainThread();
if (this.BuildFonts is not null)
{
e.OnPreBuild(
_ =>
{
var prev = ImGui.GetIO().NativePtr->Fonts;
ImGui.GetIO().NativePtr->Fonts = e.NewImAtlas.NativePtr;
((IFontAtlasBuildToolkit.IApi9Compat)e)
.FromUiBuilderObsoleteEventHandlers(() => this.BuildFonts?.InvokeSafely());
ImGui.GetIO().NativePtr->Fonts = prev;
});
}
if (this.AfterBuildFonts is not null)
{
e.OnPostBuild(
_ =>
{
var prev = ImGui.GetIO().NativePtr->Fonts;
ImGui.GetIO().NativePtr->Fonts = e.NewImAtlas.NativePtr;
((IFontAtlasBuildToolkit.IApi9Compat)e)
.FromUiBuilderObsoleteEventHandlers(() => this.AfterBuildFonts?.InvokeSafely());
ImGui.GetIO().NativePtr->Fonts = prev;
});
}
}
private void OnResizeBuffers() private void OnResizeBuffers()
{ {
this.ResizeBuffers?.InvokeSafely(); this.ResizeBuffers?.InvokeSafely();

View file

@ -52,7 +52,7 @@ public sealed class DalamudPluginInterface : IDisposable
var dataManager = Service<DataManager>.Get(); var dataManager = Service<DataManager>.Get();
var localization = Service<Localization>.Get(); var localization = Service<Localization>.Get();
this.UiBuilder = new UiBuilder(plugin.Name, plugin); this.UiBuilder = new UiBuilder(plugin.Name);
this.configs = Service<PluginManager>.Get().PluginConfigs; this.configs = Service<PluginManager>.Get().PluginConfigs;
this.Reason = reason; this.Reason = reason;

View file

@ -6,8 +6,8 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dalamud.Configuration.Internal; using Dalamud.Configuration.Internal;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.ImGuiNotification.Internal; using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Logging.Internal; using Dalamud.Logging.Internal;
using Dalamud.Plugin.Internal.Types.Manifest; using Dalamud.Plugin.Internal.Types.Manifest;

View file

@ -4,11 +4,9 @@ using System.Reflection;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dalamud.Common.Game;
using Dalamud.Configuration.Internal; using Dalamud.Configuration.Internal;
using Dalamud.Game; using Dalamud.Game;
using Dalamud.Game.Gui.Dtr; using Dalamud.Game.Gui.Dtr;
using Dalamud.Interface.GameFonts;
using Dalamud.Interface.Internal; using Dalamud.Interface.Internal;
using Dalamud.IoC.Internal; using Dalamud.IoC.Internal;
using Dalamud.Logging.Internal; using Dalamud.Logging.Internal;
@ -629,12 +627,6 @@ internal class LocalPlugin : IDisposable
config.LoadInMemory = true; config.LoadInMemory = true;
config.PreferSharedTypes = false; config.PreferSharedTypes = false;
// Pin Lumina and its dependencies recursively (compatibility behavior).
// It currently only pulls in System.* anyway.
// TODO(api10): Remove this. We don't want to pin Lumina anymore, plugins should be able to provide their own.
config.SharedAssemblies.Add((typeof(Lumina.GameData).Assembly.GetName(), true));
config.SharedAssemblies.Add((typeof(Lumina.Excel.ExcelSheetImpl).Assembly.GetName(), true));
// Make sure that plugins do not load their own Dalamud assembly. // Make sure that plugins do not load their own Dalamud assembly.
// We do not pin this recursively; if a plugin loads its own assembly of Dalamud, it is always wrong, // We do not pin this recursively; if a plugin loads its own assembly of Dalamud, it is always wrong,
// but plugins may load other versions of assemblies that Dalamud depends on. // but plugins may load other versions of assemblies that Dalamud depends on.

View file

@ -1,16 +1,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Utility;
namespace Dalamud.Plugin.Services; namespace Dalamud.Plugin.Services;
/// <summary> /// <summary>
/// This collection represents the currently spawned FFXIV game objects. /// This collection represents the currently spawned FFXIV game objects.
/// </summary> /// </summary>
[Api10ToDo( public interface IObjectTable : IEnumerable<GameObject>
"Make it an IEnumerable<GameObject> instead. Skipping null objects make IReadOnlyCollection<T>.Count yield incorrect values.")]
public interface IObjectTable : IReadOnlyCollection<GameObject>
{ {
/// <summary> /// <summary>
/// Gets the address of the object table. /// Gets the address of the object table.

View file

@ -22,22 +22,18 @@ namespace Dalamud.Storage;
/// This is not an early-loaded service, as it is needed before they are initialized. /// This is not an early-loaded service, as it is needed before they are initialized.
/// </remarks> /// </remarks>
[ServiceManager.ProvidedService] [ServiceManager.ProvidedService]
[Api10ToDo("Make internal and IInternalDisposableService, and remove #pragma guard from the caller.")] internal class ReliableFileStorage : IInternalDisposableService
public class ReliableFileStorage : IPublicDisposableService
{ {
private static readonly ModuleLog Log = new("VFS"); private static readonly ModuleLog Log = new("VFS");
private readonly object syncRoot = new(); private readonly object syncRoot = new();
private SQLiteConnection? db; private SQLiteConnection? db;
private bool isService;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ReliableFileStorage"/> class. /// Initializes a new instance of the <see cref="ReliableFileStorage"/> class.
/// </summary> /// </summary>
/// <param name="vfsDbPath">Path to the VFS.</param> /// <param name="vfsDbPath">Path to the VFS.</param>
[Obsolete("Dalamud internal use only.", false)]
[Api10ToDo("Make internal, and remove #pragma guard from the caller.")]
public ReliableFileStorage(string vfsDbPath) public ReliableFileStorage(string vfsDbPath)
{ {
var databasePath = Path.Combine(vfsDbPath, "dalamudVfs.db"); var databasePath = Path.Combine(vfsDbPath, "dalamudVfs.db");
@ -290,23 +286,12 @@ public class ReliableFileStorage : IPublicDisposableService
} }
} }
/// <inheritdoc/>
public void Dispose()
{
if (!this.isService)
this.DisposeCore();
}
/// <inheritdoc/> /// <inheritdoc/>
void IInternalDisposableService.DisposeService() void IInternalDisposableService.DisposeService()
{ {
if (this.isService) this.DisposeCore();
this.DisposeCore();
} }
/// <inheritdoc/>
void IPublicDisposableService.MarkDisposeOnlyFromService() => this.isService = true;
/// <summary> /// <summary>
/// Replace possible non-portable parts of a path with portable versions. /// Replace possible non-portable parts of a path with portable versions.
/// </summary> /// </summary>