Merge pull request #1581 from Soreepeong/more-earlyloadedservices

Use EarlyLoadedService for anything that is not mandatory for kicking off plugin loader
This commit is contained in:
goat 2024-04-09 23:59:25 +02:00 committed by GitHub
commit 9c75a9a23e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 185 additions and 112 deletions

View file

@ -20,7 +20,7 @@ namespace Dalamud.Data;
/// </summary>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<IDataManager>]
#pragma warning restore SA1015

View file

@ -26,7 +26,7 @@ namespace Dalamud.Game;
/// <summary>
/// Chat events and public helper functions.
/// </summary>
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal class ChatHandlers : IServiceType
{
// private static readonly Dictionary<string, string> UnicodeToDiscordEmojiDict = new()

View file

@ -14,7 +14,7 @@ namespace Dalamud.Game.ClientState.Aetherytes;
/// </summary>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<IAetheryteList>]
#pragma warning restore SA1015

View file

@ -16,7 +16,7 @@ namespace Dalamud.Game.ClientState.Buddy;
/// </summary>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<IBuddyList>]
#pragma warning restore SA1015

View file

@ -22,7 +22,7 @@ namespace Dalamud.Game.ClientState;
/// This class represents the state of the game client at the time of access.
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal sealed class ClientState : IInternalDisposableService, IClientState
{
private static readonly ModuleLog Log = new("ClientState");

View file

@ -9,8 +9,8 @@ namespace Dalamud.Game.ClientState.Conditions;
/// Provides access to conditions (generally player state). You can check whether a player is in combat, mounted, etc.
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
internal sealed partial class Condition : IInternalDisposableService, ICondition
[ServiceManager.EarlyLoadedService]
internal sealed class Condition : IInternalDisposableService, ICondition
{
/// <summary>
/// Gets the current max number of conditions. You can get this just by looking at the condition sheet and how many rows it has.

View file

@ -14,7 +14,7 @@ namespace Dalamud.Game.ClientState.Fates;
/// </summary>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<IFateTable>]
#pragma warning restore SA1015

View file

@ -17,7 +17,7 @@ namespace Dalamud.Game.ClientState.GamePad;
/// </summary>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<IGamepadState>]
#pragma warning restore SA1015

View file

@ -15,7 +15,7 @@ namespace Dalamud.Game.ClientState.JobGauge;
/// </summary>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<IJobGauges>]
#pragma warning restore SA1015

View file

@ -24,7 +24,7 @@ namespace Dalamud.Game.ClientState.Keys;
/// </remarks>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<IKeyState>]
#pragma warning restore SA1015

View file

@ -24,7 +24,7 @@ namespace Dalamud.Game.ClientState.Objects;
/// </summary>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<IObjectTable>]
#pragma warning restore SA1015

View file

@ -12,7 +12,7 @@ namespace Dalamud.Game.ClientState.Objects;
/// </summary>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<ITargetManager>]
#pragma warning restore SA1015

View file

@ -15,7 +15,7 @@ namespace Dalamud.Game.ClientState.Party;
/// </summary>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<IPartyList>]
#pragma warning restore SA1015

View file

@ -18,7 +18,7 @@ namespace Dalamud.Game.Command;
/// This class manages registered in-game slash commands.
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal sealed class CommandManager : IInternalDisposableService, ICommandManager
{
private static readonly ModuleLog Log = new("Command");

View file

@ -14,7 +14,7 @@ namespace Dalamud.Game.Config;
/// This class represents the game's configuration.
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal sealed class GameConfig : IInternalDisposableService, IGameConfig
{
private readonly TaskCompletionSource tcsInitialization = new();

View file

@ -12,7 +12,7 @@ namespace Dalamud.Game.DutyState;
/// This class represents the state of the currently occupied duty.
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal unsafe class DutyState : IInternalDisposableService, IDutyState
{
private readonly DutyStateAddressResolver address;

View file

@ -22,15 +22,13 @@ namespace Dalamud.Game;
/// This class represents the Framework of the native game client and grants access to various subsystems.
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal sealed class Framework : IInternalDisposableService, IFramework
{
private static readonly ModuleLog Log = new("Framework");
private static readonly Stopwatch StatsStopwatch = new();
private readonly GameLifecycle lifecycle;
private readonly Stopwatch updateStopwatch = new();
private readonly HitchDetector hitchDetector;
@ -38,6 +36,9 @@ internal sealed class Framework : IInternalDisposableService, IFramework
private readonly Hook<OnRealDestroyDelegate> destroyHook;
private readonly FrameworkAddressResolver addressResolver;
[ServiceManager.ServiceDependency]
private readonly GameLifecycle lifecycle = Service<GameLifecycle>.Get();
[ServiceManager.ServiceDependency]
private readonly DalamudConfiguration configuration = Service<DalamudConfiguration>.Get();
@ -51,9 +52,8 @@ internal sealed class Framework : IInternalDisposableService, IFramework
private ulong tickCounter;
[ServiceManager.ServiceConstructor]
private Framework(TargetSigScanner sigScanner, GameLifecycle lifecycle)
private Framework(TargetSigScanner sigScanner)
{
this.lifecycle = lifecycle;
this.hitchDetector = new HitchDetector("FrameworkUpdate", this.configuration.FrameworkUpdateHitch);
this.addressResolver = new FrameworkAddressResolver();
@ -90,7 +90,7 @@ internal sealed class Framework : IInternalDisposableService, IFramework
/// <summary>
/// Executes during FrameworkUpdate before all <see cref="Update"/> delegates.
/// </summary>
internal event IFramework.OnUpdateDelegate BeforeUpdate;
internal event IFramework.OnUpdateDelegate? BeforeUpdate;
/// <summary>
/// Gets or sets a value indicating whether the collection of stats is enabled.

View file

@ -11,7 +11,7 @@ namespace Dalamud.Game;
/// </summary>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<IGameLifecycle>]
#pragma warning restore SA1015

View file

@ -12,6 +12,7 @@ using Dalamud.IoC;
using Dalamud.IoC.Internal;
using Dalamud.Logging.Internal;
using Dalamud.Memory;
using Dalamud.Plugin.Internal;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Client.System.String;
@ -28,7 +29,7 @@ namespace Dalamud.Game.Gui;
/// This class handles interacting with the native chat UI.
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui
{
private static readonly ModuleLog Log = new("ChatGui");

View file

@ -21,7 +21,7 @@ namespace Dalamud.Game.Gui.Dtr;
/// Class used to interface with the server info bar.
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
{
private const uint BaseNodeId = 1000;

View file

@ -15,7 +15,7 @@ namespace Dalamud.Game.Gui.FlyText;
/// This class facilitates interacting with and creating native in-game "fly text".
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal sealed class FlyTextGui : IInternalDisposableService, IFlyTextGui
{
/// <summary>

View file

@ -26,7 +26,7 @@ namespace Dalamud.Game.Gui;
/// A class handling many aspects of the in-game UI.
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui
{
private static readonly ModuleLog Log = new("GameGui");

View file

@ -14,7 +14,7 @@ namespace Dalamud.Game.Gui.PartyFinder;
/// This class handles interacting with the native PartyFinder window.
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal sealed class PartyFinderGui : IInternalDisposableService, IPartyFinderGui
{
private readonly PartyFinderAddressResolver address;

View file

@ -13,7 +13,7 @@ namespace Dalamud.Game.Gui.Toast;
/// This class facilitates interacting with and creating native toast windows.
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal sealed partial class ToastGui : IInternalDisposableService, IToastGui
{
private const uint QuestToastCheckmarkMagic = 60081;

View file

@ -18,7 +18,7 @@ namespace Dalamud.Game.Inventory;
/// This class provides events for the players in-game inventory.
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal class GameInventory : IInternalDisposableService
{
private readonly List<GameInventoryPluginScoped> subscribersPendingChange = new();

View file

@ -13,7 +13,7 @@ namespace Dalamud.Game.Libc;
/// </summary>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<ILibcFunction>]
#pragma warning restore SA1015

View file

@ -14,7 +14,7 @@ namespace Dalamud.Game.Network;
/// This class handles interacting with game network events.
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal sealed class GameNetwork : IInternalDisposableService, IGameNetwork
{
private readonly GameNetworkAddressResolver address;

View file

@ -25,7 +25,7 @@ namespace Dalamud.Game.Network.Internal;
/// <summary>
/// This class handles network notifications and uploading market board data.
/// </summary>
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal unsafe class NetworkHandlers : IInternalDisposableService
{
private readonly IMarketBoardUploader uploader;

View file

@ -14,7 +14,7 @@ namespace Dalamud.Hooking.WndProcHook;
/// <summary>
/// Manages WndProc hooks for game main window and extra ImGui viewport windows.
/// </summary>
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal sealed class WndProcHookManager : IInternalDisposableService
{
private static readonly ModuleLog Log = new(nameof(WndProcHookManager));

View file

@ -15,7 +15,7 @@ namespace Dalamud.Interface.DragDrop;
/// and can be used to create ImGui drag and drop sources and targets for those external events.
/// </summary>
[PluginInterface]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<IDragDropManager>]
#pragma warning restore SA1015

View file

@ -51,7 +51,7 @@ namespace Dalamud.Interface.Internal;
/// <summary>
/// This class manages interaction with the ImGui interface.
/// </summary>
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal class InterfaceManager : IInternalDisposableService
{
/// <summary>

View file

@ -22,7 +22,7 @@ namespace Dalamud.Interface.Internal;
/// </summary>
[PluginInterface]
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
#pragma warning disable SA1015
[ResolveVia<ITextureProvider>]
[ResolveVia<ITextureSubstitutionProvider>]

View file

@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Reflection;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility;
@ -96,7 +97,7 @@ internal class ServicesWidget : IDataWindowWidget
var rowWidth = 0f;
foreach (var node in levelNodes)
rowWidth += ImGui.CalcTextSize(node.TypeName).X + cellPad.X + margin.X;
rowWidth += node.DisplayedNameSize.X + cellPad.X + margin.X;
var off = cellPad / 2;
if (rowWidth < width)
@ -107,7 +108,7 @@ internal class ServicesWidget : IDataWindowWidget
foreach (var node in levelNodes)
{
var textSize = ImGui.CalcTextSize(node.TypeName);
var textSize = node.DisplayedNameSize;
var cellSize = textSize + cellPad;
var rc = new Vector4(pos + off, pos.X + off.X + cellSize.X, pos.Y + off.Y + cellSize.Y);
@ -174,7 +175,7 @@ internal class ServicesWidget : IDataWindowWidget
{
foreach (var node in levelNodes)
{
var textSize = ImGui.CalcTextSize(node.TypeName);
var textSize = node.DisplayedNameSize;
var cellSize = textSize + cellPad;
var rc = this.nodeRects[node];
@ -188,8 +189,19 @@ internal class ServicesWidget : IDataWindowWidget
dl.AddRectFilled(new(rc.X, rc.Y), new(rc.Z, rc.W), rectHoverRelatedFillColor);
dl.AddRect(new(rc.X, rc.Y), new(rc.Z, rc.W), rectBaseBorderColor);
ImGui.SetCursorScreenPos(new(rc.X, rc.Y));
ImGui.InvisibleButton(node.DisplayedName, new(rc.Z - rc.X, rc.W - rc.Y));
if (ImGui.IsItemHovered() && node.BlockingReason is not null)
ImGui.SetTooltip(node.BlockingReason);
ImGui.SetCursorPos((new Vector2(rc.X, rc.Y) - pos) + ((cellSize - textSize) / 2));
ImGui.TextUnformatted(node.TypeName);
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
ImGui.TextUnformatted(node.DisplayedName);
ImGui.SameLine();
ImGui.PushStyleColor(ImGuiCol.Text, node.TypeSuffixColor);
ImGui.TextUnformatted(node.TypeSuffix);
ImGui.PopStyleVar();
ImGui.PopStyleColor();
}
}
@ -259,11 +271,44 @@ internal class ServicesWidget : IDataWindowWidget
private readonly List<ServiceDependencyNode> children = new();
private readonly List<ServiceDependencyNode> invalidParents = new();
private ServiceDependencyNode(Type t) => this.Type = t;
private ServiceDependencyNode(Type t)
{
this.Type = t;
this.BlockingReason =
t.GetCustomAttribute<ServiceManager.BlockingEarlyLoadedServiceAttribute>()?.BlockReason;
this.Kind = t.GetCustomAttribute<ServiceManager.ServiceAttribute>()?.Kind ??
ServiceManager.ServiceKind.None;
this.DisplayedName = this.Type.Name;
this.TypeSuffix = this.Kind switch {
ServiceManager.ServiceKind.ProvidedService => " (P)",
ServiceManager.ServiceKind.EarlyLoadedService => " (E)",
ServiceManager.ServiceKind.BlockingEarlyLoadedService => " (B)",
ServiceManager.ServiceKind.ScopedService => " (S)",
var x => $" (? {x})",
};
this.TypeSuffixColor = this.Kind switch {
ServiceManager.ServiceKind.ProvidedService => ImGui.GetColorU32(ImGuiColors.DalamudGrey),
ServiceManager.ServiceKind.EarlyLoadedService => ImGui.GetColorU32(ImGuiColors.DalamudWhite),
ServiceManager.ServiceKind.BlockingEarlyLoadedService => ImGui.GetColorU32(ImGuiColors.ParsedPink),
ServiceManager.ServiceKind.ScopedService => ImGui.GetColorU32(ImGuiColors.ParsedGreen),
_ => ImGui.GetColorU32(ImGuiColors.DalamudRed),
};
}
public Type Type { get; }
public string TypeName => this.Type.Name;
public string DisplayedName { get; }
public string TypeSuffix { get; }
public uint TypeSuffixColor { get; }
public Vector2 DisplayedNameSize =>
ImGui.CalcTextSize(this.DisplayedName) + ImGui.CalcTextSize(this.TypeSuffix) with { Y = 0 };
public ServiceManager.ServiceKind Kind { get; }
public string? BlockingReason { get; }
public IReadOnlyList<ServiceDependencyNode> Parents => this.parents;

View file

@ -25,7 +25,7 @@ public class ProfilerWindow : Window
/// Initializes a new instance of the <see cref="ProfilerWindow"/> class.
/// </summary>
public ProfilerWindow()
: base("Profiler", forceMainWindow: true)
: base("Profiler")
{
}

View file

@ -29,7 +29,7 @@ namespace Dalamud.Interface.ManagedFontAtlas.Internals;
/// <summary>
/// Factory for the implementation of <see cref="IFontAtlas"/>.
/// </summary>
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal sealed partial class FontAtlasFactory
: IInternalDisposableService, GamePrebakedFontHandle.IGameFontTextureProvider
{

View file

@ -15,7 +15,7 @@ namespace Dalamud.Interface;
/// Class responsible for managing elements in the title screen menu.
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal class TitleScreenMenu : IServiceType, ITitleScreenMenu
{
/// <summary>

View file

@ -3,6 +3,7 @@ using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using Dalamud.Plugin.Internal;
using Dalamud.Utility;
namespace Dalamud.Networking.Http;
@ -11,7 +12,9 @@ namespace Dalamud.Networking.Http;
/// A service to help build and manage HttpClients with some semblance of Happy Eyeballs (RFC 8305 - IPv4 fallback)
/// awareness.
/// </summary>
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.BlockingEarlyLoadedService($"{nameof(PluginManager)} currently uses this.")]
// ^ TODO: This seems unnecessary, remove the hard dependency at a later time.
// Otherwise, if PM eventually marks this class as required, note that in the comment above.
internal class HappyHttpClient : IInternalDisposableService
{
/// <summary>

View file

@ -39,22 +39,10 @@ namespace Dalamud.Plugin.Internal;
/// <summary>
/// Class responsible for loading and unloading plugins.
/// NOTE: ALL plugin exposed services are marked as dependencies for PluginManager in Service{T}.
/// NOTE: ALL plugin exposed services are marked as dependencies for <see cref="PluginManager"/>
/// from <see cref="ResolvePossiblePluginDependencyServices"/>.
/// </summary>
[ServiceManager.BlockingEarlyLoadedService]
#pragma warning disable SA1015
// DalamudTextureWrap registers textures to dispose with IM
[InherentDependency<InterfaceManager>]
// LocalPlugin uses ServiceContainer to create scopes
[InherentDependency<ServiceContainer>]
// DalamudPluginInterface hands out a reference to this, so we have to keep it around
// TODO api9: make it a service
[InherentDependency<DataShare>]
#pragma warning restore SA1015
[ServiceManager.BlockingEarlyLoadedService("Accomodation of plugins that blocks the game startup.")]
internal partial class PluginManager : IInternalDisposableService
{
/// <summary>
@ -72,7 +60,7 @@ internal partial class PluginManager : IInternalDisposableService
private readonly List<RemotePluginManifest> availablePluginsList = new();
private readonly List<AvailablePluginUpdate> updatablePluginsList = new();
private readonly DalamudLinkPayload openInstallerWindowPluginChangelogsLink;
private readonly Task<DalamudLinkPayload> openInstallerWindowPluginChangelogsLink;
[ServiceManager.ServiceDependency]
private readonly DalamudConfiguration configuration = Service<DalamudConfiguration>.Get();
@ -86,9 +74,6 @@ internal partial class PluginManager : IInternalDisposableService
[ServiceManager.ServiceDependency]
private readonly HappyHttpClient happyHttpClient = Service<HappyHttpClient>.Get();
[ServiceManager.ServiceDependency]
private readonly ChatGui chatGui = Service<ChatGui>.Get();
static PluginManager()
{
DalamudApiLevel = typeof(PluginManager).Assembly.GetName().Version!.Major;
@ -137,10 +122,16 @@ internal partial class PluginManager : IInternalDisposableService
throw new InvalidDataException("Couldn't deserialize banned plugins manifest.");
}
this.openInstallerWindowPluginChangelogsLink = this.chatGui.AddChatLinkHandler("Dalamud", 1003, (_, _) =>
{
Service<DalamudInterface>.GetNullable()?.OpenPluginInstallerTo(PluginInstallerWindow.PluginInstallerOpenKind.Changelogs);
});
this.openInstallerWindowPluginChangelogsLink =
Service<ChatGui>.GetAsync().ContinueWith(
chatGuiTask => chatGuiTask.Result.AddChatLinkHandler(
"Dalamud",
1003,
(_, _) =>
{
Service<DalamudInterface>.GetNullable()?.OpenPluginInstallerTo(
PluginInstallerWindow.PluginInstallerOpenKind.Changelogs);
}));
this.configuration.PluginTestingOptIns ??= new();
this.MainRepo = PluginRepository.CreateMainRepo(this.happyHttpClient);
@ -304,41 +295,54 @@ internal partial class PluginManager : IInternalDisposableService
/// <param name="updateMetadata">The list of updated plugin metadata.</param>
/// <param name="header">The header text to send to chat prior to any update info.</param>
public void PrintUpdatedPlugins(List<PluginUpdateStatus>? updateMetadata, string header)
{
if (updateMetadata is { Count: > 0 })
{
this.chatGui.Print(new XivChatEntry
=> Service<ChatGui>.GetAsync().ContinueWith(
chatGuiTask =>
{
Message = new SeString(new List<Payload>()
{
new TextPayload(header),
new TextPayload(" ["),
new UIForegroundPayload(500),
this.openInstallerWindowPluginChangelogsLink,
new TextPayload(Loc.Localize("DalamudInstallerPluginChangelogHelp", "Open plugin changelogs")),
RawPayload.LinkTerminator,
new UIForegroundPayload(0),
new TextPayload("]"),
}),
});
if (!chatGuiTask.IsCompletedSuccessfully)
return;
foreach (var metadata in updateMetadata)
{
if (metadata.Status == PluginUpdateStatus.StatusKind.Success)
var chatGui = chatGuiTask.Result;
if (updateMetadata is { Count: > 0 })
{
this.chatGui.Print(Locs.DalamudPluginUpdateSuccessful(metadata.Name, metadata.Version));
}
else
{
this.chatGui.Print(new XivChatEntry
chatGui.Print(
new XivChatEntry
{
Message = new SeString(
new List<Payload>()
{
new TextPayload(header),
new TextPayload(" ["),
new UIForegroundPayload(500),
this.openInstallerWindowPluginChangelogsLink.Result,
new TextPayload(
Loc.Localize("DalamudInstallerPluginChangelogHelp", "Open plugin changelogs")),
RawPayload.LinkTerminator,
new UIForegroundPayload(0),
new TextPayload("]"),
}),
});
foreach (var metadata in updateMetadata)
{
Message = Locs.DalamudPluginUpdateFailed(metadata.Name, metadata.Version, PluginUpdateStatus.LocalizeUpdateStatusKind(metadata.Status)),
Type = XivChatType.Urgent,
});
if (metadata.Status == PluginUpdateStatus.StatusKind.Success)
{
chatGui.Print(Locs.DalamudPluginUpdateSuccessful(metadata.Name, metadata.Version));
}
else
{
chatGui.Print(
new XivChatEntry
{
Message = Locs.DalamudPluginUpdateFailed(
metadata.Name,
metadata.Version,
PluginUpdateStatus.LocalizeUpdateStatusKind(metadata.Status)),
Type = XivChatType.Urgent,
});
}
}
}
}
}
}
});
/// <summary>
/// For a given manifest, determine if the user opted into testing this plugin.
@ -1257,6 +1261,16 @@ internal partial class PluginManager : IInternalDisposableService
/// <returns>The dependency services.</returns>
private static IEnumerable<Type> ResolvePossiblePluginDependencyServices()
{
// DalamudPluginInterface hands out a reference to this, so we have to keep it around.
// TODO api9: make it a service
yield return typeof(DataShare);
// DalamudTextureWrap registers textures to dispose with IM.
yield return typeof(InterfaceManager);
// Note: LocalPlugin uses ServiceContainer to create scopes, but it is done outside PM ctor.
// This is not required: yield return typeof(ServiceContainer);
foreach (var serviceType in ServiceManager.GetConcreteServiceTypes())
{
if (serviceType == typeof(PluginManager))

View file

@ -15,7 +15,7 @@ namespace Dalamud.Plugin.Internal.Profiles;
/// <summary>
/// Class responsible for managing plugin profiles.
/// </summary>
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.BlockingEarlyLoadedService($"Data provider for {nameof(PluginManager)}.")]
internal class ProfileManager : IServiceType
{
private static readonly ModuleLog Log = new("PROFMAN");

View file

@ -11,7 +11,7 @@ namespace Dalamud.Plugin.Ipc.Internal;
/// <summary>
/// This class facilitates sharing data-references of standard types between plugins without using more expensive IPC.
/// </summary>
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.EarlyLoadedService]
internal class DataShare : IServiceType
{
/// <summary>

View file

@ -638,10 +638,15 @@ internal static class ServiceManager
/// <summary>
/// Initializes a new instance of the <see cref="BlockingEarlyLoadedServiceAttribute"/> class.
/// </summary>
public BlockingEarlyLoadedServiceAttribute()
/// <param name="blockReason">Reason of blocking the game startup.</param>
public BlockingEarlyLoadedServiceAttribute(string blockReason)
: base(ServiceKind.BlockingEarlyLoadedService)
{
this.BlockReason = blockReason;
}
/// <summary>Gets the reason of blocking the startup of the game.</summary>
public string BlockReason { get; }
}
/// <summary>

View file

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using Dalamud.IoC;
using Dalamud.IoC.Internal;
using Dalamud.Utility;
using Dalamud.Utility.Timing;
using JetBrains.Annotations;
@ -198,13 +199,16 @@ internal static class Service<T> where T : IServiceType
.ToArray();
if (offenders.Any())
{
ServiceManager.Log.Error(
"{me} is a {bels}; it can only depend on {bels} and {ps}.\nOffending dependencies:\n{offenders}",
typeof(T),
nameof(ServiceManager.BlockingEarlyLoadedServiceAttribute),
nameof(ServiceManager.BlockingEarlyLoadedServiceAttribute),
nameof(ServiceManager.ProvidedServiceAttribute),
string.Join("\n", offenders.Select(x => $"\t* {x.Name}")));
const string bels = nameof(ServiceManager.BlockingEarlyLoadedServiceAttribute);
const string ps = nameof(ServiceManager.ProvidedServiceAttribute);
var errmsg =
$"{typeof(T)} is a {bels}; it can only depend on {bels} and {ps}.\nOffending dependencies:\n" +
string.Join("\n", offenders.Select(x => $"\t* {x.Name}"));
#if DEBUG
Util.Fatal(errmsg, "Service Dependency Check");
#else
ServiceManager.Log.Error(errmsg);
#endif
}
}

View file

@ -23,7 +23,8 @@ namespace Dalamud.Storage.Assets;
/// A concrete class for <see cref="IDalamudAssetManager"/>.
/// </summary>
[PluginInterface]
[ServiceManager.BlockingEarlyLoadedService]
[ServiceManager.BlockingEarlyLoadedService(
"Ensuring that it is worth continuing loading Dalamud, by checking if all required assets are properly available.")]
#pragma warning disable SA1015
[ResolveVia<IDalamudAssetManager>]
#pragma warning restore SA1015