Merge pull request #2434 from Haselnussbomber/service-provider
Some checks failed
Build Dalamud / Build on Windows (push) Waiting to run
Build Dalamud / Check API Compatibility (push) Blocked by required conditions
Build Dalamud / Deploy dalamud-distrib staging (push) Blocked by required conditions
Rollup changes to next version / check (api14) (push) Failing after 6s
Tag Build / Tag Build (push) Successful in 1s

Simpler plugin service dependency injection
This commit is contained in:
goat 2025-11-17 23:04:45 +01:00 committed by GitHub
commit e65f441105
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
48 changed files with 184 additions and 227 deletions

View file

@ -18,7 +18,7 @@ namespace Dalamud.IoC.Internal;
/// Dalamud services are constructed via Service{T}.ConstructObject at the moment.
/// </summary>
[ServiceManager.ProvidedService]
internal class ServiceContainer : IServiceProvider, IServiceType
internal class ServiceContainer : IServiceType
{
private static readonly ModuleLog Log = new("SERVICECONTAINER");
@ -160,10 +160,21 @@ internal class ServiceContainer : IServiceProvider, IServiceType
/// <returns>An implementation of a service scope.</returns>
public IServiceScope GetScope() => new ServiceScopeImpl(this);
/// <inheritdoc/>
object? IServiceProvider.GetService(Type serviceType) => this.GetSingletonService(serviceType);
private async Task<object> GetService(Type serviceType, ServiceScopeImpl? scope, object[] scopedObjects)
/// <summary>
/// Resolves and returns an instance of the specified service type, using either singleton or scoped lifetime as
/// appropriate.
/// </summary>
/// <param name="serviceType">The type of the service to resolve. This must be a concrete or interface type registered with the service
/// manager.</param>
/// <param name="scope">The scope within which to create scoped services. Required if the requested service type is registered as
/// scoped; otherwise, can be null.</param>
/// <param name="scopedObjects">An array of objects available for scoped resolution. Used to locate or create scoped service instances when
/// applicable.</param>
/// <returns>An instance of the requested service type. Returns a singleton instance if available, a scoped instance if
/// required, or an object from the provided scoped objects if it matches the service type.</returns>
/// <exception cref="InvalidOperationException">Thrown if a scoped service is requested but no scope is provided, or if the requested service type cannot be
/// resolved from the scoped objects.</exception>
public async Task<object> GetService(Type serviceType, ServiceScopeImpl? scope, object[] scopedObjects)
{
if (this.interfaceToTypeMap.TryGetValue(serviceType, out var implementingType))
serviceType = implementingType;

View file

@ -1,4 +1,4 @@
using System.Collections.Concurrent;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@ -12,7 +12,7 @@ namespace Dalamud.IoC.Internal;
/// <summary>
/// Container enabling the creation of scoped services.
/// </summary>
internal interface IServiceScope : IAsyncDisposable
internal interface IServiceScope : IServiceProvider, IAsyncDisposable
{
/// <summary>
/// Register objects that may be injected to scoped services,
@ -57,6 +57,12 @@ internal class ServiceScopeImpl : IServiceScope
/// <param name="container">The container this scope will use to create services.</param>
public ServiceScopeImpl(ServiceContainer container) => this.container = container;
/// <inheritdoc/>
public object? GetService(Type serviceType)
{
return this.container.GetService(serviceType, this, []).ConfigureAwait(false).GetAwaiter().GetResult();
}
/// <inheritdoc/>
public void RegisterPrivateScopes(params object[] scopes)
{

View file

@ -86,126 +86,73 @@ internal sealed class DalamudPluginInterface : IDalamudPluginInterface, IDisposa
configuration.DalamudConfigurationSaved += this.OnDalamudConfigurationSaved;
}
/// <summary>
/// Event that gets fired when loc is changed
/// </summary>
/// <inheritdoc/>
public event IDalamudPluginInterface.LanguageChangedDelegate? LanguageChanged;
/// <summary>
/// Event that is fired when the active list of plugins is changed.
/// </summary>
/// <inheritdoc/>
public event IDalamudPluginInterface.ActivePluginsChangedDelegate? ActivePluginsChanged;
/// <summary>
/// Gets the reason this plugin was loaded.
/// </summary>
/// <inheritdoc/>
public PluginLoadReason Reason { get; }
/// <summary>
/// Gets a value indicating whether auto-updates have already completed this session.
/// </summary>
/// <inheritdoc/>
public bool IsAutoUpdateComplete => Service<AutoUpdateManager>.GetNullable()?.IsAutoUpdateComplete ?? false;
/// <summary>
/// Gets the repository from which this plugin was installed.
///
/// If a plugin was installed from the official/main repository, this will return the value of
/// <see cref="SpecialPluginSource.MainRepo"/>. Developer plugins will return the value of
/// <see cref="SpecialPluginSource.DevPlugin"/>.
/// </summary>
/// <inheritdoc/>
public string SourceRepository { get; }
/// <summary>
/// Gets the current internal plugin name.
/// </summary>
/// <inheritdoc/>
public string InternalName => this.plugin.InternalName;
/// <summary>
/// Gets the plugin's manifest.
/// </summary>
/// <inheritdoc/>
public IPluginManifest Manifest => this.plugin.Manifest;
/// <summary>
/// Gets a value indicating whether this is a dev plugin.
/// </summary>
/// <inheritdoc/>
public bool IsDev => this.plugin.IsDev;
/// <summary>
/// Gets a value indicating whether this is a testing release of a plugin.
/// </summary>
/// <remarks>
/// Dev plugins have undefined behavior for this value, but can be expected to return <c>false</c>.
/// </remarks>
/// <inheritdoc/>
public bool IsTesting { get; }
/// <summary>
/// Gets the time that this plugin was loaded.
/// </summary>
/// <inheritdoc/>
public DateTime LoadTime { get; }
/// <summary>
/// Gets the UTC time that this plugin was loaded.
/// </summary>
/// <inheritdoc/>
public DateTime LoadTimeUTC { get; }
/// <summary>
/// Gets the timespan delta from when this plugin was loaded.
/// </summary>
/// <inheritdoc/>
public TimeSpan LoadTimeDelta => DateTime.Now - this.LoadTime;
/// <summary>
/// Gets the directory Dalamud assets are stored in.
/// </summary>
/// <inheritdoc/>
public DirectoryInfo DalamudAssetDirectory => Service<Dalamud>.Get().AssetDirectory;
/// <summary>
/// Gets the location of your plugin assembly.
/// </summary>
/// <inheritdoc/>
public FileInfo AssemblyLocation => this.plugin.DllFile;
/// <summary>
/// Gets the directory your plugin configurations are stored in.
/// </summary>
/// <inheritdoc/>
public DirectoryInfo ConfigDirectory => new(this.GetPluginConfigDirectory());
/// <summary>
/// Gets the config file of your plugin.
/// </summary>
/// <inheritdoc/>
public FileInfo ConfigFile => this.configs.GetConfigFile(this.plugin.InternalName);
/// <summary>
/// Gets the <see cref="UiBuilder"/> instance which allows you to draw UI into the game via ImGui draw calls.
/// </summary>
/// <inheritdoc/>
public IUiBuilder UiBuilder { get; private set; }
/// <summary>
/// Gets a value indicating whether Dalamud is running in Debug mode or the /xldev menu is open. This can occur on release builds.
/// </summary>
/// <inheritdoc/>
public bool IsDevMenuOpen => Service<DalamudInterface>.GetNullable() is { IsDevMenuOpen: true }; // Can be null during boot
/// <summary>
/// Gets a value indicating whether a debugger is attached.
/// </summary>
/// <inheritdoc/>
public bool IsDebugging => Debugger.IsAttached;
/// <summary>
/// Gets the current UI language in two-letter iso format.
/// </summary>
/// <inheritdoc/>
public string UiLanguage { get; private set; }
/// <summary>
/// Gets serializer class with functions to remove special characters from strings.
/// </summary>
/// <inheritdoc/>
public ISanitizer Sanitizer { get; }
/// <summary>
/// Gets the chat type used by default for plugin messages.
/// </summary>
/// <inheritdoc/>
public XivChatType GeneralChatType { get; private set; }
/// <summary>
/// Gets a list of installed plugins along with their current state.
/// </summary>
/// <inheritdoc/>
public IEnumerable<IExposedPlugin> InstalledPlugins =>
Service<PluginManager>.Get().InstalledPlugins.Select(p => new ExposedPlugin(p));
@ -214,12 +161,7 @@ internal sealed class DalamudPluginInterface : IDalamudPluginInterface, IDisposa
/// </summary>
internal UiBuilder LocalUiBuilder => this.uiBuilder;
/// <summary>
/// Opens the <see cref="PluginInstallerWindow"/>, with an optional search term.
/// </summary>
/// <param name="openTo">The page to open the installer to. Defaults to the "All Plugins" page.</param>
/// <param name="searchText">An optional search text to input in the search box.</param>
/// <returns>Returns false if the DalamudInterface was null.</returns>
/// <inheritdoc/>
public bool OpenPluginInstallerTo(PluginInstallerOpenKind openTo = PluginInstallerOpenKind.AllPlugins, string? searchText = null)
{
var dalamudInterface = Service<DalamudInterface>.GetNullable(); // Can be null during boot
@ -234,12 +176,7 @@ internal sealed class DalamudPluginInterface : IDalamudPluginInterface, IDisposa
return true;
}
/// <summary>
/// Opens the <see cref="SettingsWindow"/>, with an optional search term.
/// </summary>
/// <param name="openTo">The tab to open the settings to. Defaults to the "General" tab.</param>
/// <param name="searchText">An optional search text to input in the search box.</param>
/// <returns>Returns false if the DalamudInterface was null.</returns>
/// <inheritdoc/>
public bool OpenDalamudSettingsTo(SettingsOpenKind openTo = SettingsOpenKind.General, string? searchText = null)
{
var dalamudInterface = Service<DalamudInterface>.GetNullable(); // Can be null during boot
@ -254,10 +191,7 @@ internal sealed class DalamudPluginInterface : IDalamudPluginInterface, IDisposa
return true;
}
/// <summary>
/// Opens the dev menu bar.
/// </summary>
/// <returns>Returns false if the DalamudInterface was null.</returns>
/// <inheritdoc/>
public bool OpenDeveloperMenu()
{
var dalamudInterface = Service<DalamudInterface>.GetNullable(); // Can be null during boot
@ -296,102 +230,91 @@ internal sealed class DalamudPluginInterface : IDalamudPluginInterface, IDisposa
#region IPC
/// <inheritdoc cref="DataShare.GetOrCreateData{T}"/>
/// <inheritdoc/>
public T GetOrCreateData<T>(string tag, Func<T> dataGenerator) where T : class
=> Service<DataShare>.Get().GetOrCreateData(tag, dataGenerator);
/// <inheritdoc cref="DataShare.RelinquishData"/>
/// <inheritdoc/>
public void RelinquishData(string tag)
=> Service<DataShare>.Get().RelinquishData(tag);
/// <inheritdoc cref="DataShare.TryGetData{T}"/>
/// <inheritdoc/>
public bool TryGetData<T>(string tag, [NotNullWhen(true)] out T? data) where T : class
=> Service<DataShare>.Get().TryGetData(tag, out data);
/// <inheritdoc cref="DataShare.GetData{T}"/>
/// <inheritdoc/>
public T? GetData<T>(string tag) where T : class
=> Service<DataShare>.Get().GetData<T>(tag);
/// <summary>
/// Gets an IPC provider.
/// </summary>
/// <typeparam name="TRet">The return type for funcs. Use object if this is unused.</typeparam>
/// <param name="name">The name of the IPC registration.</param>
/// <returns>An IPC provider.</returns>
/// <exception cref="IpcTypeMismatchError">This is thrown when the requested types do not match the previously registered types are different.</exception>
/// <inheritdoc/>
public ICallGateProvider<TRet> GetIpcProvider<TRet>(string name)
=> new CallGatePubSub<TRet>(name);
/// <inheritdoc cref="ICallGateProvider{TRet}"/>
/// <inheritdoc/>
public ICallGateProvider<T1, TRet> GetIpcProvider<T1, TRet>(string name)
=> new CallGatePubSub<T1, TRet>(name);
/// <inheritdoc cref="ICallGateProvider{TRet}"/>
/// <inheritdoc/>
public ICallGateProvider<T1, T2, TRet> GetIpcProvider<T1, T2, TRet>(string name)
=> new CallGatePubSub<T1, T2, TRet>(name);
/// <inheritdoc cref="ICallGateProvider{TRet}"/>
/// <inheritdoc/>
public ICallGateProvider<T1, T2, T3, TRet> GetIpcProvider<T1, T2, T3, TRet>(string name)
=> new CallGatePubSub<T1, T2, T3, TRet>(name);
/// <inheritdoc cref="ICallGateProvider{TRet}"/>
/// <inheritdoc/>
public ICallGateProvider<T1, T2, T3, T4, TRet> GetIpcProvider<T1, T2, T3, T4, TRet>(string name)
=> new CallGatePubSub<T1, T2, T3, T4, TRet>(name);
/// <inheritdoc cref="ICallGateProvider{TRet}"/>
/// <inheritdoc/>
public ICallGateProvider<T1, T2, T3, T4, T5, TRet> GetIpcProvider<T1, T2, T3, T4, T5, TRet>(string name)
=> new CallGatePubSub<T1, T2, T3, T4, T5, TRet>(name);
/// <inheritdoc cref="ICallGateProvider{TRet}"/>
/// <inheritdoc/>
public ICallGateProvider<T1, T2, T3, T4, T5, T6, TRet> GetIpcProvider<T1, T2, T3, T4, T5, T6, TRet>(string name)
=> new CallGatePubSub<T1, T2, T3, T4, T5, T6, TRet>(name);
/// <inheritdoc cref="ICallGateProvider{TRet}"/>
/// <inheritdoc/>
public ICallGateProvider<T1, T2, T3, T4, T5, T6, T7, TRet> GetIpcProvider<T1, T2, T3, T4, T5, T6, T7, TRet>(string name)
=> new CallGatePubSub<T1, T2, T3, T4, T5, T6, T7, TRet>(name);
/// <inheritdoc cref="ICallGateProvider{TRet}"/>
/// <inheritdoc/>
public ICallGateProvider<T1, T2, T3, T4, T5, T6, T7, T8, TRet> GetIpcProvider<T1, T2, T3, T4, T5, T6, T7, T8, TRet>(string name)
=> new CallGatePubSub<T1, T2, T3, T4, T5, T6, T7, T8, TRet>(name);
/// <summary>
/// Gets an IPC subscriber.
/// </summary>
/// <typeparam name="TRet">The return type for funcs. Use object if this is unused.</typeparam>
/// <param name="name">The name of the IPC registration.</param>
/// <returns>An IPC subscriber.</returns>
/// <inheritdoc/>
public ICallGateSubscriber<TRet> GetIpcSubscriber<TRet>(string name)
=> new CallGatePubSub<TRet>(name);
/// <inheritdoc cref="ICallGateSubscriber{TRet}"/>
/// <inheritdoc/>
public ICallGateSubscriber<T1, TRet> GetIpcSubscriber<T1, TRet>(string name)
=> new CallGatePubSub<T1, TRet>(name);
/// <inheritdoc cref="ICallGateSubscriber{TRet}"/>
/// <inheritdoc/>
public ICallGateSubscriber<T1, T2, TRet> GetIpcSubscriber<T1, T2, TRet>(string name)
=> new CallGatePubSub<T1, T2, TRet>(name);
/// <inheritdoc cref="ICallGateSubscriber{TRet}"/>
/// <inheritdoc/>
public ICallGateSubscriber<T1, T2, T3, TRet> GetIpcSubscriber<T1, T2, T3, TRet>(string name)
=> new CallGatePubSub<T1, T2, T3, TRet>(name);
/// <inheritdoc cref="ICallGateSubscriber{TRet}"/>
/// <inheritdoc/>
public ICallGateSubscriber<T1, T2, T3, T4, TRet> GetIpcSubscriber<T1, T2, T3, T4, TRet>(string name)
=> new CallGatePubSub<T1, T2, T3, T4, TRet>(name);
/// <inheritdoc cref="ICallGateSubscriber{TRet}"/>
/// <inheritdoc/>
public ICallGateSubscriber<T1, T2, T3, T4, T5, TRet> GetIpcSubscriber<T1, T2, T3, T4, T5, TRet>(string name)
=> new CallGatePubSub<T1, T2, T3, T4, T5, TRet>(name);
/// <inheritdoc cref="ICallGateSubscriber{TRet}"/>
/// <inheritdoc/>
public ICallGateSubscriber<T1, T2, T3, T4, T5, T6, TRet> GetIpcSubscriber<T1, T2, T3, T4, T5, T6, TRet>(string name)
=> new CallGatePubSub<T1, T2, T3, T4, T5, T6, TRet>(name);
/// <inheritdoc cref="ICallGateSubscriber{TRet}"/>
/// <inheritdoc/>
public ICallGateSubscriber<T1, T2, T3, T4, T5, T6, T7, TRet> GetIpcSubscriber<T1, T2, T3, T4, T5, T6, T7, TRet>(string name)
=> new CallGatePubSub<T1, T2, T3, T4, T5, T6, T7, TRet>(name);
/// <inheritdoc cref="ICallGateSubscriber{TRet}"/>
/// <inheritdoc/>
public ICallGateSubscriber<T1, T2, T3, T4, T5, T6, T7, T8, TRet> GetIpcSubscriber<T1, T2, T3, T4, T5, T6, T7, T8, TRet>(string name)
=> new CallGatePubSub<T1, T2, T3, T4, T5, T6, T7, T8, TRet>(name);
@ -399,10 +322,7 @@ internal sealed class DalamudPluginInterface : IDalamudPluginInterface, IDisposa
#region Configuration
/// <summary>
/// Save a plugin configuration(inheriting IPluginConfiguration).
/// </summary>
/// <param name="currentConfig">The current configuration.</param>
/// <inheritdoc/>
public void SavePluginConfig(IPluginConfiguration? currentConfig)
{
if (currentConfig == null)
@ -411,10 +331,7 @@ internal sealed class DalamudPluginInterface : IDalamudPluginInterface, IDisposa
this.configs.Save(currentConfig, this.plugin.InternalName, this.plugin.EffectiveWorkingPluginId);
}
/// <summary>
/// Get a previously saved plugin configuration or null if none was saved before.
/// </summary>
/// <returns>A previously saved config or null if none was saved before.</returns>
/// <inheritdoc/>
public IPluginConfiguration? GetPluginConfig()
{
// This is done to support json deserialization of plugin configurations
@ -438,22 +355,22 @@ internal sealed class DalamudPluginInterface : IDalamudPluginInterface, IDisposa
return this.configs.Load(this.plugin.InternalName, this.plugin.EffectiveWorkingPluginId);
}
/// <summary>
/// Get the config directory.
/// </summary>
/// <returns>directory with path of AppData/XIVLauncher/pluginConfig/PluginInternalName.</returns>
/// <inheritdoc/>
public string GetPluginConfigDirectory() => this.configs.GetDirectory(this.plugin.InternalName);
/// <summary>
/// Get the loc directory.
/// </summary>
/// <returns>directory with path of AppData/XIVLauncher/pluginConfig/PluginInternalName/loc.</returns>
/// <inheritdoc/>
public string GetPluginLocDirectory() => this.configs.GetDirectory(Path.Combine(this.plugin.InternalName, "loc"));
#endregion
#region Dependency Injection
/// <inheritdoc/>
public object? GetService(Type serviceType)
{
return this.plugin.ServiceScope.GetService(serviceType);
}
/// <inheritdoc/>
public T? Create<T>(params object[] scopedObjects) where T : class
{
@ -502,8 +419,7 @@ internal sealed class DalamudPluginInterface : IDalamudPluginInterface, IDisposa
#endregion
/// <summary>Unregister the plugin and dispose all references.</summary>
/// <remarks>Dalamud internal use only.</remarks>
/// <inheritdoc/>
public void Dispose()
{
Service<ChatGui>.Get().RemoveChatLinkHandler(this.plugin.InternalName);

View file

@ -8,8 +8,6 @@ using System.Threading.Tasks;
using Dalamud.Configuration;
using Dalamud.Game.Text;
using Dalamud.Game.Text.Sanitizer;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Interface;
using Dalamud.Interface.Internal.Windows.PluginInstaller;
using Dalamud.Interface.Internal.Windows.Settings;
@ -24,7 +22,7 @@ namespace Dalamud.Plugin;
/// <summary>
/// This interface acts as an interface to various objects needed to interact with Dalamud and the game.
/// </summary>
public interface IDalamudPluginInterface
public interface IDalamudPluginInterface : IServiceProvider
{
/// <summary>
/// Delegate for localization change with two-letter iso lang code.

View file

@ -1,4 +1,4 @@
using Dalamud.Game.Addon.Events;
using Dalamud.Game.Addon.Events;
using Dalamud.Game.Addon.Events.EventDataTypes;
namespace Dalamud.Plugin.Services;
@ -6,7 +6,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// Service provider for addon event management.
/// </summary>
public interface IAddonEventManager
public interface IAddonEventManager : IDalamudService
{
/// <summary>
/// Delegate to be called when an event is received.

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Dalamud.Game.Addon.Lifecycle;
@ -9,7 +9,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// This class provides events for in-game addon lifecycles.
/// </summary>
public interface IAddonLifecycle
public interface IAddonLifecycle : IDalamudService
{
/// <summary>
/// Delegate for receiving addon lifecycle event messages.

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Dalamud.Game.ClientState.Aetherytes;
@ -7,7 +7,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// This collection represents the list of available Aetherytes in the Teleport window.
/// </summary>
public interface IAetheryteList : IReadOnlyCollection<IAetheryteEntry>
public interface IAetheryteList : IDalamudService, IReadOnlyCollection<IAetheryteEntry>
{
/// <summary>
/// Gets the amount of Aetherytes the local player has unlocked.

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Dalamud.Game.ClientState.Buddy;
@ -8,7 +8,7 @@ namespace Dalamud.Plugin.Services;
/// This collection represents the buddies present in your squadron or trust party.
/// It does not include the local player.
/// </summary>
public interface IBuddyList : IReadOnlyCollection<IBuddyMember>
public interface IBuddyList : IDalamudService, IReadOnlyCollection<IBuddyMember>
{
/// <summary>
/// Gets the amount of battle buddies the local player has.

View file

@ -10,7 +10,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// This class handles interacting with the native chat UI.
/// </summary>
public interface IChatGui
public interface IChatGui : IDalamudService
{
/// <summary>
/// A delegate type used with the <see cref="ChatGui.ChatMessage"/> event.

View file

@ -8,7 +8,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// This class represents the state of the game client at the time of access.
/// </summary>
public interface IClientState
public interface IClientState : IDalamudService
{
/// <summary>
/// A delegate type used for the <see cref="ClassJobChanged"/> event.

View file

@ -1,4 +1,4 @@
using System.Collections.ObjectModel;
using System.Collections.ObjectModel;
using Dalamud.Game.Command;
@ -7,7 +7,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// This class manages registered in-game slash commands.
/// </summary>
public interface ICommandManager
public interface ICommandManager : IDalamudService
{
/// <summary>
/// Gets a read-only list of all registered commands.

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Dalamud.Game.ClientState.Conditions;
@ -7,7 +7,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// Provides access to conditions (generally player state). You can check whether a player is in combat, mounted, etc.
/// </summary>
public interface ICondition
public interface ICondition : IDalamudService
{
/// <summary>
/// A delegate type used with the <see cref="ConditionChange"/> event.

View file

@ -1,4 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
using Dalamud.Console;
@ -8,7 +8,7 @@ namespace Dalamud.Plugin.Services;
/// Provides functions to register console commands and variables.
/// </summary>
[Experimental("Dalamud001")]
public interface IConsole
public interface IConsole : IDalamudService
{
/// <summary>
/// Gets this plugin's namespace prefix, derived off its internal name.

View file

@ -5,7 +5,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// This class provides methods for interacting with the game's context menu.
/// </summary>
public interface IContextMenu
public interface IContextMenu : IDalamudService
{
/// <summary>
/// A delegate type used for the <see cref="OnMenuOpened"/> event.

View file

@ -0,0 +1,10 @@
namespace Dalamud.Plugin.Services;
/// <summary>
/// Marker interface for Dalamud services.
/// </summary>
/// <remarks>
/// This interface is implemented by all services provided through Dalamud's
/// dependency injection system.
/// </remarks>
public interface IDalamudService;

View file

@ -14,7 +14,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// This class provides data for Dalamud-internal features, but can also be used by plugins if needed.
/// </summary>
public interface IDataManager
public interface IDataManager : IDalamudService
{
/// <summary>
/// Gets the current game client language.

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Dalamud.Game.Gui.Dtr;
using Dalamud.Game.Text.SeStringHandling;
@ -8,7 +8,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// Class used to interface with the server info bar.
/// </summary>
public interface IDtrBar
public interface IDtrBar : IDalamudService
{
/// <summary>
/// Gets a read-only copy of the list of all DTR bar entries.

View file

@ -1,9 +1,9 @@
namespace Dalamud.Plugin.Services;
namespace Dalamud.Plugin.Services;
/// <summary>
/// This class represents the state of the currently occupied duty.
/// </summary>
public interface IDutyState
public interface IDutyState : IDalamudService
{
/// <summary>
/// Event that gets fired when the duty starts.

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Dalamud.Game.ClientState.Fates;
@ -7,7 +7,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// This collection represents the currently available Fate events.
/// </summary>
public interface IFateTable : IReadOnlyCollection<IFate>
public interface IFateTable : IDalamudService, IReadOnlyCollection<IFate>
{
/// <summary>
/// Gets the address of the Fate table.

View file

@ -1,4 +1,4 @@
using Dalamud.Game.Gui.FlyText;
using Dalamud.Game.Gui.FlyText;
using Dalamud.Game.Text.SeStringHandling;
namespace Dalamud.Plugin.Services;
@ -6,7 +6,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// This class facilitates interacting with and creating native in-game "fly text".
/// </summary>
public interface IFlyTextGui
public interface IFlyTextGui : IDalamudService
{
/// <summary>
/// The delegate defining the type for the FlyText event.

View file

@ -1,4 +1,4 @@
using System.Threading;
using System.Threading;
using System.Threading.Tasks;
using Dalamud.Interface.Internal.Windows.Data.Widgets;
@ -24,7 +24,7 @@ namespace Dalamud.Plugin.Services;
/// <para>See <see cref="TaskSchedulerWidget"/> to see the difference in behaviors, and how would a misuse of these
/// functions result in a deadlock.</para>
/// </remarks>
public interface IFramework
public interface IFramework : IDalamudService
{
/// <summary>
/// A delegate type used with the <see cref="Update"/> event.

View file

@ -1,4 +1,4 @@
using System.Diagnostics;
using System.Diagnostics;
using Dalamud.Game.Config;
using Dalamud.Plugin.Internal.Types;
@ -17,7 +17,7 @@ namespace Dalamud.Plugin.Services;
/// If property access from the plugin constructor is desired, do the value retrieval asynchronously via
/// <see cref="IFramework.RunOnFrameworkThread{T}(Func{T})"/>; do not wait for the result right away.
/// </remarks>
public interface IGameConfig
public interface IGameConfig : IDalamudService
{
/// <summary>
/// Event which is fired when any game config option is changed.

View file

@ -9,7 +9,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// A class handling many aspects of the in-game UI.
/// </summary>
public unsafe interface IGameGui
public unsafe interface IGameGui : IDalamudService
{
/// <summary>
/// Event which is fired when the game UI hiding is toggled.

View file

@ -1,4 +1,4 @@
using System.Diagnostics;
using System.Diagnostics;
using Dalamud.Hooking;
using Dalamud.Utility.Signatures;
@ -8,7 +8,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// Service responsible for the creation of hooks.
/// </summary>
public interface IGameInteropProvider
public interface IGameInteropProvider : IDalamudService
{
/// <summary>
/// Available hooking backends.

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Dalamud.Game.Inventory;
using Dalamud.Game.Inventory.InventoryEventArgTypes;
@ -8,7 +8,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// This class provides events for the in-game inventory.
/// </summary>
public interface IGameInventory
public interface IGameInventory : IDalamudService
{
/// <summary>
/// Delegate function to be called when inventories have been changed.

View file

@ -1,11 +1,11 @@
using System.Threading;
using System.Threading;
namespace Dalamud.Plugin.Services;
/// <summary>
/// Class offering cancellation tokens for common gameplay events.
/// </summary>
public interface IGameLifecycle
public interface IGameLifecycle : IDalamudService
{
/// <summary>
/// Gets a token that is cancelled when Dalamud is unloading.

View file

@ -1,4 +1,4 @@
using Dalamud.Game.Network;
using Dalamud.Game.Network;
namespace Dalamud.Plugin.Services;
@ -6,7 +6,7 @@ namespace Dalamud.Plugin.Services;
/// This class handles interacting with game network events.
/// </summary>
[Obsolete("Will be removed in a future release. Use packet handler hooks instead.", true)]
public interface IGameNetwork
public interface IGameNetwork : IDalamudService
{
// TODO(v9): we shouldn't be passing pointers to the actual data here

View file

@ -1,4 +1,4 @@
using System.Numerics;
using System.Numerics;
using Dalamud.Bindings.ImGui;
using Dalamud.Game.ClientState.GamePad;
@ -10,7 +10,7 @@ namespace Dalamud.Plugin.Services;
///
/// Will block game's gamepad input if <see cref="ImGuiConfigFlags.NavEnableGamepad"/> is set.
/// </summary>
public interface IGamepadState
public interface IGamepadState : IDalamudService
{
/// <summary>
/// Gets the pointer to the current instance of the GamepadInput struct.

View file

@ -1,11 +1,11 @@
using Dalamud.Game.ClientState.JobGauge.Types;
using Dalamud.Game.ClientState.JobGauge.Types;
namespace Dalamud.Plugin.Services;
/// <summary>
/// This class converts in-memory Job gauge data to structs.
/// </summary>
public interface IJobGauges
public interface IJobGauges : IDalamudService
{
/// <summary>
/// Gets the address of the JobGauge data.

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Dalamud.Game.ClientState.Keys;
@ -16,7 +16,7 @@ namespace Dalamud.Plugin.Services;
/// index &amp; 2 = key up (ephemeral).
/// index &amp; 3 = short key press (ephemeral).
/// </remarks>
public interface IKeyState
public interface IKeyState : IDalamudService
{
/// <summary>
/// Get or set the key-pressed state for a given vkCode.

View file

@ -1,11 +1,11 @@
using Dalamud.Game.Network.Structures;
using Dalamud.Game.Network.Structures;
namespace Dalamud.Plugin.Services;
/// <summary>
/// Provides access to market board related events as the client receives/sends them.
/// </summary>
public interface IMarketBoard
public interface IMarketBoard : IDalamudService
{
/// <summary>
/// A delegate type used with the <see cref="HistoryReceived"/> event.

View file

@ -7,7 +7,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// Class used to modify the data used when rendering nameplates.
/// </summary>
public interface INamePlateGui
public interface INamePlateGui : IDalamudService
{
/// <summary>
/// The delegate used for receiving nameplate update events.

View file

@ -3,7 +3,7 @@ using Dalamud.Interface.ImGuiNotification;
namespace Dalamud.Plugin.Services;
/// <summary>Manager for notifications provided by Dalamud using ImGui.</summary>
public interface INotificationManager
public interface INotificationManager : IDalamudService
{
/// <summary>Adds a notification.</summary>
/// <param name="notification">The new notification.</param>

View file

@ -8,7 +8,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// This collection represents the currently spawned FFXIV game objects.
/// </summary>
public interface IObjectTable : IEnumerable<IGameObject>
public interface IObjectTable : IDalamudService, IEnumerable<IGameObject>
{
/// <summary>
/// Gets the address of the object table.

View file

@ -1,11 +1,11 @@
using Dalamud.Game.Gui.PartyFinder.Types;
using Dalamud.Game.Gui.PartyFinder.Types;
namespace Dalamud.Plugin.Services;
/// <summary>
/// This class handles interacting with the native PartyFinder window.
/// </summary>
public interface IPartyFinderGui
public interface IPartyFinderGui : IDalamudService
{
/// <summary>
/// Event type fired each time the game receives an individual Party Finder listing.

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Dalamud.Game.ClientState.Party;
@ -7,7 +7,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// This collection represents the actors present in your party or alliance.
/// </summary>
public interface IPartyList : IReadOnlyCollection<IPartyMember>
public interface IPartyList : IDalamudService, IReadOnlyCollection<IPartyMember>
{
/// <summary>
/// Gets the amount of party members the local player has.

View file

@ -12,7 +12,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// Interface for determining the players state.
/// </summary>
public interface IPlayerState
public interface IPlayerState : IDalamudService
{
/// <summary>
/// Gets a value indicating whether the local players data is loaded.

View file

@ -1,4 +1,4 @@
using Serilog;
using Serilog;
using Serilog.Events;
#pragma warning disable CS1573 // See https://github.com/dotnet/roslyn/issues/40325
@ -8,7 +8,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// An opinionated service to handle logging for plugins.
/// </summary>
public interface IPluginLog
public interface IPluginLog : IDalamudService
{
/// <summary>
/// Gets a Serilog ILogger instance for this plugin. This is the entrypoint for plugins that wish to use more

View file

@ -9,7 +9,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// Defines a service for retrieving localized text for various in-game entities.
/// </summary>
public interface ISeStringEvaluator
public interface ISeStringEvaluator : IDalamudService
{
/// <summary>
/// Evaluates macros in a <see cref="ReadOnlySeString"/>.

View file

@ -2,12 +2,14 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Dalamud.Plugin.Services;
namespace Dalamud.Game;
/// <summary>
/// A SigScanner facilitates searching for memory signatures in a given ProcessModule.
/// </summary>
public interface ISigScanner
public interface ISigScanner : IDalamudService
{
/// <summary>
/// Gets a value indicating whether the search on this module is performed on a copy.

View file

@ -1,11 +1,12 @@
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin.Services;
namespace Dalamud.Game.ClientState.Objects;
/// <summary>
/// Get and set various kinds of targets for the player.
/// </summary>
public interface ITargetManager
public interface ITargetManager : IDalamudService
{
/// <summary>
/// Gets or sets the current target.

View file

@ -32,7 +32,7 @@ namespace Dalamud.Plugin.Services;
/// <see cref="TexWidget"/>.
/// </para>
/// </remarks>
public interface ITextureProvider
public interface ITextureProvider : IDalamudService
{
/// <summary>Creates an empty texture.</summary>
/// <param name="specs">Texture specifications.</param>

View file

@ -3,14 +3,13 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Dalamud.Interface.Internal;
using Dalamud.Interface.Textures;
using Dalamud.Interface.Textures.TextureWraps;
namespace Dalamud.Plugin.Services;
/// <summary>Service that grants you to read instances of <see cref="IDalamudTextureWrap"/>.</summary>
public interface ITextureReadbackProvider
public interface ITextureReadbackProvider : IDalamudService
{
/// <summary>Gets the raw data of a texture wrap.</summary>
/// <param name="wrap">The source texture wrap.</param>

View file

@ -1,11 +1,11 @@
using System.Collections.Generic;
using System.Collections.Generic;
namespace Dalamud.Plugin.Services;
/// <summary>
/// Service that grants you the ability to replace texture data that is to be loaded by Dalamud.
/// </summary>
public interface ITextureSubstitutionProvider
public interface ITextureSubstitutionProvider : IDalamudService
{
/// <summary>
/// Delegate describing a function that may be used to intercept and replace texture data.

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Dalamud.Interface;
using Dalamud.Interface.Textures;
@ -8,7 +8,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// Interface for class responsible for managing elements in the title screen menu.
/// </summary>
public interface ITitleScreenMenu
public interface ITitleScreenMenu : IDalamudService
{
/// <summary>
/// Gets the list of read only entries in the title screen menu.

View file

@ -1,4 +1,4 @@
using Dalamud.Game.Gui.Toast;
using Dalamud.Game.Gui.Toast;
using Dalamud.Game.Text.SeStringHandling;
namespace Dalamud.Plugin.Services;
@ -6,7 +6,7 @@ namespace Dalamud.Plugin.Services;
/// <summary>
/// This class facilitates interacting with and creating native toast windows.
/// </summary>
public interface IToastGui
public interface IToastGui : IDalamudService
{
/// <summary>
/// A delegate type used when a normal toast window appears.

View file

@ -11,7 +11,7 @@ namespace Dalamud.Plugin.Services;
/// Interface for determining unlock state of various content in the game.
/// </summary>
[Experimental("UnlockState")]
public interface IUnlockState
public interface IUnlockState : IDalamudService
{
/// <summary>
/// A delegate type used for the <see cref="Unlock"/> event.

View file

@ -9,11 +9,14 @@ using System.Threading.Tasks;
using Dalamud.Configuration.Internal;
using Dalamud.Game;
using Dalamud.IoC;
using Dalamud.IoC.Internal;
using Dalamud.Logging.Internal;
using Dalamud.Plugin.Services;
using Dalamud.Storage;
using Dalamud.Utility;
using Dalamud.Utility.Timing;
using JetBrains.Annotations;
// API10 TODO: Move to Dalamud.Service namespace. Some plugins reflect this... including my own, oops. There's a todo
@ -541,9 +544,11 @@ internal static class ServiceManager
if (attr == null)
return ServiceKind.None;
Debug.Assert(
type.IsAssignableTo(typeof(IServiceType)),
"Service did not inherit from IServiceType");
if (!type.IsAssignableTo(typeof(IServiceType)))
{
Log.Error($"Service {type.Name} did not inherit from IServiceType");
Debug.Fail("Service did not inherit from IServiceType");
}
if (attr.IsAssignableTo(typeof(BlockingEarlyLoadedServiceAttribute)))
return ServiceKind.BlockingEarlyLoadedService;
@ -552,7 +557,16 @@ internal static class ServiceManager
return ServiceKind.EarlyLoadedService;
if (attr.IsAssignableTo(typeof(ScopedServiceAttribute)))
{
if (type.GetCustomAttribute<PluginInterfaceAttribute>() != null
&& !type.IsAssignableTo(typeof(IDalamudService)))
{
Log.Error($"Plugin-scoped service {type.Name} must inherit from IDalamudService");
Debug.Fail("Plugin-scoped service must inherit from IDalamudService");
}
return ServiceKind.ScopedService;
}
return ServiceKind.ProvidedService;
}