mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
Implement ioc container
This commit is contained in:
parent
ff1d7f2829
commit
2fe8ccb1da
14 changed files with 247 additions and 248 deletions
|
|
@ -17,16 +17,11 @@ namespace Dalamud.CorePlugin
|
||||||
|
|
||||||
// private Localization localizationManager;
|
// private Localization localizationManager;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public string Name => "Dalamud.CorePlugin";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the plugin interface.
|
/// Initializes a new instance of the <see cref="PluginImpl"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal DalamudPluginInterface Interface { get; private set; }
|
/// <param name="pluginInterface">Dalamud plugin interface.</param>
|
||||||
|
public PluginImpl(DalamudPluginInterface pluginInterface)
|
||||||
/// <inheritdoc/>
|
|
||||||
public void Initialize(DalamudPluginInterface pluginInterface)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -38,8 +33,7 @@ namespace Dalamud.CorePlugin
|
||||||
this.Interface.UiBuilder.Draw += this.OnDraw;
|
this.Interface.UiBuilder.Draw += this.OnDraw;
|
||||||
this.Interface.UiBuilder.OpenConfigUi += this.OnOpenConfigUi;
|
this.Interface.UiBuilder.OpenConfigUi += this.OnOpenConfigUi;
|
||||||
|
|
||||||
var commandManager = Service<CommandManager>.Get();
|
Service<CommandManager>.Get().AddHandler("/di", new(this.OnCommand) { HelpMessage = $"Access the {this.Name} plugin." });
|
||||||
commandManager.AddHandler("/di", new(this.OnCommand) { HelpMessage = $"Access the {this.Name} plugin." });
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -47,10 +41,18 @@ namespace Dalamud.CorePlugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public string Name => "Dalamud.CorePlugin";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the plugin interface.
|
||||||
|
/// </summary>
|
||||||
|
internal DalamudPluginInterface Interface { get; private set; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
this.Interface.CommandManager.RemoveHandler("/di");
|
Service<CommandManager>.Get().RemoveHandler("/di");
|
||||||
|
|
||||||
this.Interface.UiBuilder.Draw -= this.OnDraw;
|
this.Interface.UiBuilder.Draw -= this.OnDraw;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,10 +91,11 @@ namespace Dalamud
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
Service<ServiceContainer>.Set();
|
||||||
|
|
||||||
// Initialize the process information.
|
// Initialize the process information.
|
||||||
Service<SigScanner>.Set(new SigScanner(true));
|
Service<SigScanner>.Set(new SigScanner(true));
|
||||||
Service<HookManager>.Set();
|
Service<HookManager>.Set();
|
||||||
Service<ServiceContainer>.Set();
|
|
||||||
|
|
||||||
// Initialize FFXIVClientStructs function resolver
|
// Initialize FFXIVClientStructs function resolver
|
||||||
FFXIVClientStructs.Resolver.Initialize();
|
FFXIVClientStructs.Resolver.Initialize();
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
using Dalamud.IoC;
|
||||||
|
using Dalamud.IoC.Internal;
|
||||||
|
|
||||||
namespace Dalamud.Game.ClientState.Conditions
|
namespace Dalamud.Game.ClientState.Conditions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides access to conditions (generally player state). You can check whether a player is in combat, mounted, etc.
|
/// Provides access to conditions (generally player state). You can check whether a player is in combat, mounted, etc.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[PluginInterface]
|
||||||
|
[InterfaceVersion("1.0")]
|
||||||
public class Condition
|
public class Condition
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
using Dalamud.Game.ClientState.JobGauge.Types;
|
using Dalamud.Game.ClientState.JobGauge.Types;
|
||||||
|
using Dalamud.IoC;
|
||||||
|
using Dalamud.IoC.Internal;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace Dalamud.Game.ClientState.JobGauge
|
namespace Dalamud.Game.ClientState.JobGauge
|
||||||
|
|
@ -10,6 +12,8 @@ namespace Dalamud.Game.ClientState.JobGauge
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This class converts in-memory Job gauge data to structs.
|
/// This class converts in-memory Job gauge data to structs.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[PluginInterface]
|
||||||
|
[InterfaceVersion("1.0")]
|
||||||
public class JobGauges
|
public class JobGauges
|
||||||
{
|
{
|
||||||
private Dictionary<Type, JobGaugeBase> cache = new();
|
private Dictionary<Type, JobGaugeBase> cache = new();
|
||||||
|
|
|
||||||
|
|
@ -46,11 +46,10 @@ namespace Dalamud.Game.Gui
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal GameGui()
|
internal GameGui()
|
||||||
{
|
{
|
||||||
this.address = new GameGuiAddressResolver(this.address.BaseAddress);
|
this.address = new GameGuiAddressResolver();
|
||||||
this.address.Setup();
|
this.address.Setup();
|
||||||
|
|
||||||
Log.Verbose("===== G A M E G U I =====");
|
Log.Verbose("===== G A M E G U I =====");
|
||||||
|
|
||||||
Log.Verbose($"GameGuiManager address 0x{this.address.BaseAddress.ToInt64():X}");
|
Log.Verbose($"GameGuiManager address 0x{this.address.BaseAddress.ToInt64():X}");
|
||||||
Log.Verbose($"SetGlobalBgm address 0x{this.address.SetGlobalBgm.ToInt64():X}");
|
Log.Verbose($"SetGlobalBgm address 0x{this.address.SetGlobalBgm.ToInt64():X}");
|
||||||
Log.Verbose($"HandleItemHover address 0x{this.address.HandleItemHover.ToInt64():X}");
|
Log.Verbose($"HandleItemHover address 0x{this.address.HandleItemHover.ToInt64():X}");
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,9 @@ namespace Dalamud.Game.Gui
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="GameGuiAddressResolver"/> class.
|
/// Initializes a new instance of the <see cref="GameGuiAddressResolver"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="baseAddress">The base address of the native GuiManager class.</param>
|
public GameGuiAddressResolver()
|
||||||
public GameGuiAddressResolver(IntPtr baseAddress)
|
|
||||||
{
|
{
|
||||||
this.BaseAddress = baseAddress;
|
this.BaseAddress = Service<Framework>.Get().Address.BaseAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Dalamud.IoC;
|
||||||
|
using Dalamud.IoC.Internal;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Microsoft.CodeAnalysis.CSharp.Scripting;
|
using Microsoft.CodeAnalysis.CSharp.Scripting;
|
||||||
|
|
@ -79,13 +80,18 @@ namespace Dalamud.Interface.Internal.Scratchpad
|
||||||
{
|
{
|
||||||
var script = CSharpScript.Create(code, options);
|
var script = CSharpScript.Create(code, options);
|
||||||
|
|
||||||
var pi = new DalamudPluginInterface("Scratch-" + doc.Id, PluginLoadReason.Unknown);
|
var pluginType = script.ContinueWith<Type>("return typeof(ScratchPlugin);")
|
||||||
var plugin = script.ContinueWith<IDalamudPlugin>("return new ScratchPlugin() as IDalamudPlugin;")
|
|
||||||
.RunAsync().GetAwaiter().GetResult().ReturnValue;
|
.RunAsync().GetAwaiter().GetResult().ReturnValue;
|
||||||
|
|
||||||
plugin.Initialize(pi);
|
var pi = new DalamudPluginInterface($"Scratch-{doc.Id}", PluginLoadReason.Unknown);
|
||||||
|
|
||||||
this.loadedScratches[doc.Id] = plugin;
|
var ioc = Service<ServiceContainer>.Get();
|
||||||
|
var plugin = ioc.Create(pluginType, pi);
|
||||||
|
|
||||||
|
if (plugin == null)
|
||||||
|
throw new Exception("Could not initialize scratch plugin");
|
||||||
|
|
||||||
|
this.loadedScratches[doc.Id] = (IDalamudPlugin)plugin;
|
||||||
return ScratchLoadStatus.Success;
|
return ScratchLoadStatus.Success;
|
||||||
}
|
}
|
||||||
catch (CompilationErrorException ex)
|
catch (CompilationErrorException ex)
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ public class ScratchPlugin : IDalamudPlugin {
|
||||||
|
|
||||||
{SETUPBODY}
|
{SETUPBODY}
|
||||||
|
|
||||||
public void Initialize(DalamudPluginInterface pluginInterface)
|
public ScratchPlugin(DalamudPluginInterface pluginInterface)
|
||||||
{
|
{
|
||||||
this.pi = pluginInterface;
|
this.pi = pluginInterface;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -610,53 +610,6 @@ namespace Dalamud.Interface.Internal.Windows
|
||||||
|
|
||||||
private void DrawPluginIPC()
|
private void DrawPluginIPC()
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0618 // Type or member is obsolete
|
|
||||||
var i1 = new DalamudPluginInterface("DalamudTestSub", PluginLoadReason.Unknown);
|
|
||||||
var i2 = new DalamudPluginInterface("DalamudTestPub", PluginLoadReason.Unknown);
|
|
||||||
|
|
||||||
if (ImGui.Button("Add test sub"))
|
|
||||||
{
|
|
||||||
i1.Subscribe("DalamudTestPub", o =>
|
|
||||||
{
|
|
||||||
dynamic msg = o;
|
|
||||||
Log.Debug(msg.Expand);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.Button("Add test sub any"))
|
|
||||||
{
|
|
||||||
i1.SubscribeAny((o, a) =>
|
|
||||||
{
|
|
||||||
dynamic msg = a;
|
|
||||||
Log.Debug($"From {o}: {msg.Expand}");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.Button("Remove test sub"))
|
|
||||||
i1.Unsubscribe("DalamudTestPub");
|
|
||||||
|
|
||||||
if (ImGui.Button("Remove test sub any"))
|
|
||||||
i1.UnsubscribeAny();
|
|
||||||
|
|
||||||
if (ImGui.Button("Send test message"))
|
|
||||||
{
|
|
||||||
dynamic testMsg = new ExpandoObject();
|
|
||||||
testMsg.Expand = "dong";
|
|
||||||
i2.SendMessage(testMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This doesn't actually work, so don't mind it - impl relies on plugins being registered in PluginManager
|
|
||||||
if (ImGui.Button("Send test message any"))
|
|
||||||
{
|
|
||||||
dynamic testMsg = new ExpandoObject();
|
|
||||||
testMsg.Expand = "dong";
|
|
||||||
i2.SendMessage("DalamudTestSub", testMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
var pluginManager = Service<PluginManager>.Get();
|
|
||||||
foreach (var ipc in pluginManager.IpcSubscriptions)
|
|
||||||
ImGui.Text($"Source:{ipc.SourcePluginName} Sub:{ipc.SubPluginName}");
|
|
||||||
#pragma warning restore CS0618 // Type or member is obsolete
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawCondition()
|
private void DrawCondition()
|
||||||
|
|
|
||||||
31
Dalamud/IoC/Internal/ObjectInstance.cs
Normal file
31
Dalamud/IoC/Internal/ObjectInstance.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Dalamud.IoC.Internal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An object instance registered in the <see cref="ServiceContainer"/>.
|
||||||
|
/// </summary>
|
||||||
|
internal class ObjectInstance
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ObjectInstance"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="instance">The underlying instance.</param>
|
||||||
|
public ObjectInstance(object instance)
|
||||||
|
{
|
||||||
|
this.Instance = new WeakReference(instance);
|
||||||
|
this.Version = instance.GetType().GetCustomAttribute<InterfaceVersionAttribute>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current version of the instance, if it exists.
|
||||||
|
/// </summary>
|
||||||
|
public InterfaceVersionAttribute? Version { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a reference to the underlying instance.
|
||||||
|
/// </summary>
|
||||||
|
public WeakReference Instance { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
161
Dalamud/IoC/Internal/ServiceContainer.cs
Normal file
161
Dalamud/IoC/Internal/ServiceContainer.cs
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Dalamud.IoC.Internal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A simple singleton-only IOC container that provides (optional) version-based dependency resolution.
|
||||||
|
/// </summary>
|
||||||
|
internal class ServiceContainer : IServiceProvider
|
||||||
|
{
|
||||||
|
private readonly Dictionary<Type, ObjectInstance> instances = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register a singleton object of any type into the current IOC container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="instance">The existing instance to register in the container.</param>
|
||||||
|
/// <typeparam name="T">The interface to register.</typeparam>
|
||||||
|
public void RegisterSingleton<T>(T instance)
|
||||||
|
{
|
||||||
|
if (instance == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(instance));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.instances[typeof(T)] = new(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">The type of object to create.</param>
|
||||||
|
/// <param name="scopedObjects">Scoped objects to be included in the constructor.</param>
|
||||||
|
/// <returns>The created object.</returns>
|
||||||
|
public object? Create(Type objectType, params object[] scopedObjects)
|
||||||
|
{
|
||||||
|
var ctor = this.FindApplicableCtor(objectType, scopedObjects);
|
||||||
|
if (ctor == null)
|
||||||
|
{
|
||||||
|
Log.Error("Failed to create {TypeName}, unable to find any services to satisfy the dependencies in the ctor", objectType.FullName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate dependency versions (if they exist)
|
||||||
|
var parameters = ctor.GetParameters().Select(p =>
|
||||||
|
{
|
||||||
|
var parameterType = p.ParameterType;
|
||||||
|
var requiredVersion = p.GetCustomAttribute(typeof(RequiredVersionAttribute)) as RequiredVersionAttribute;
|
||||||
|
return (parameterType, requiredVersion);
|
||||||
|
});
|
||||||
|
|
||||||
|
var versionCheck = parameters.Any(p =>
|
||||||
|
{
|
||||||
|
// if there's no required version, ignore it
|
||||||
|
if (p.requiredVersion == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// if there's no requested version, ignore it
|
||||||
|
var declVersion = p.parameterType.GetCustomAttribute<InterfaceVersionAttribute>();
|
||||||
|
if (declVersion == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (declVersion.Version == p.requiredVersion.Version)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Log.Error(
|
||||||
|
"Requested version {ReqVersion} does not match the implemented version {ImplVersion} for param type {ParamType}",
|
||||||
|
p.requiredVersion.Version,
|
||||||
|
declVersion.Version,
|
||||||
|
p.parameterType.FullName);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!versionCheck)
|
||||||
|
{
|
||||||
|
Log.Error("Failed to create {TypeName}, a RequestedVersion could not be satisfied", objectType.FullName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var resolvedParams = parameters
|
||||||
|
.Select(p =>
|
||||||
|
{
|
||||||
|
var service = this.GetService(p.parameterType, scopedObjects);
|
||||||
|
|
||||||
|
if (service == null)
|
||||||
|
{
|
||||||
|
Log.Error("Requested service type {TypeName} could not be satisfied", p.parameterType.FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return service;
|
||||||
|
})
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
var hasNull = resolvedParams.Any(p => p == null);
|
||||||
|
if (hasNull)
|
||||||
|
{
|
||||||
|
Log.Error("Failed to create {TypeName}, a requested service type could not be satisfied", objectType.FullName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Activator.CreateInstance(objectType, resolvedParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
object? IServiceProvider.GetService(Type serviceType) => this.GetService(serviceType);
|
||||||
|
|
||||||
|
private object? GetService(Type serviceType, object[] scopedObjects)
|
||||||
|
{
|
||||||
|
var singletonService = this.GetService(serviceType);
|
||||||
|
if (singletonService != null)
|
||||||
|
{
|
||||||
|
return singletonService;
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve dependency from scoped objects
|
||||||
|
var scoped = scopedObjects.FirstOrDefault(o => o.GetType() == serviceType);
|
||||||
|
if (scoped == default)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scoped;
|
||||||
|
}
|
||||||
|
|
||||||
|
private object? GetService(Type serviceType)
|
||||||
|
{
|
||||||
|
var hasInstance = this.instances.TryGetValue(serviceType, out var service);
|
||||||
|
if (hasInstance && service.Instance.IsAlive)
|
||||||
|
{
|
||||||
|
return service.Instance.Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConstructorInfo? FindApplicableCtor(Type type, object[] scopedObjects)
|
||||||
|
{
|
||||||
|
// get a list of all the available types: scoped and singleton
|
||||||
|
var types = scopedObjects
|
||||||
|
.Select(o => o.GetType())
|
||||||
|
.Union(this.instances.Keys);
|
||||||
|
|
||||||
|
var ctors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
foreach (var ctor in ctors)
|
||||||
|
{
|
||||||
|
var parameters = ctor.GetParameters();
|
||||||
|
|
||||||
|
var success = parameters.All(p => types.Contains(p.ParameterType));
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
return ctor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -39,22 +39,17 @@ namespace Dalamud.Plugin
|
||||||
internal DalamudPluginInterface(string pluginName, PluginLoadReason reason)
|
internal DalamudPluginInterface(string pluginName, PluginLoadReason reason)
|
||||||
{
|
{
|
||||||
var configuration = Service<DalamudConfiguration>.Get();
|
var configuration = Service<DalamudConfiguration>.Get();
|
||||||
|
var dataManager = Service<DataManager>.Get();
|
||||||
var localization = Service<Localization>.Get();
|
var localization = Service<Localization>.Get();
|
||||||
|
|
||||||
this.CommandManager = Service<CommandManager>.Get();
|
|
||||||
this.Framework = Service<Framework>.Get();
|
|
||||||
this.ClientState = Service<ClientState>.Get();
|
|
||||||
this.UiBuilder = new UiBuilder(pluginName);
|
this.UiBuilder = new UiBuilder(pluginName);
|
||||||
this.TargetModuleScanner = Service<SigScanner>.Get();
|
|
||||||
this.Data = Service<DataManager>.Get();
|
|
||||||
this.SeStringManager = Service<SeStringManager>.Get();
|
|
||||||
|
|
||||||
this.pluginName = pluginName;
|
this.pluginName = pluginName;
|
||||||
this.configs = Service<PluginManager>.Get().PluginConfigs;
|
this.configs = Service<PluginManager>.Get().PluginConfigs;
|
||||||
this.Reason = reason;
|
this.Reason = reason;
|
||||||
|
|
||||||
this.GeneralChatType = configuration.GeneralChatType;
|
this.GeneralChatType = configuration.GeneralChatType;
|
||||||
this.Sanitizer = new Sanitizer(this.Data.Language);
|
this.Sanitizer = new Sanitizer(dataManager.Language);
|
||||||
if (configuration.LanguageOverride != null)
|
if (configuration.LanguageOverride != null)
|
||||||
{
|
{
|
||||||
this.UiLanguage = configuration.LanguageOverride;
|
this.UiLanguage = configuration.LanguageOverride;
|
||||||
|
|
@ -103,41 +98,11 @@ namespace Dalamud.Plugin
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public FileInfo ConfigFile => this.configs.GetConfigFile(this.pluginName);
|
public FileInfo ConfigFile => this.configs.GetConfigFile(this.pluginName);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the CommandManager object that allows you to add and remove custom chat commands.
|
|
||||||
/// </summary>
|
|
||||||
public CommandManager CommandManager { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the ClientState object that allows you to access current client memory information like actors, territories, etc.
|
|
||||||
/// </summary>
|
|
||||||
public ClientState ClientState { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the Framework object that allows you to interact with the client.
|
|
||||||
/// </summary>
|
|
||||||
public Framework Framework { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="UiBuilder"/> instance which allows you to draw UI into the game via ImGui draw calls.
|
/// Gets the <see cref="UiBuilder"/> instance which allows you to draw UI into the game via ImGui draw calls.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public UiBuilder UiBuilder { get; private set; }
|
public UiBuilder UiBuilder { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="SigScanner">SigScanner</see> instance targeting the main module of the FFXIV process.
|
|
||||||
/// </summary>
|
|
||||||
public SigScanner TargetModuleScanner { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="DataManager">DataManager</see> instance which allows you to access game data needed by the main dalamud features.
|
|
||||||
/// </summary>
|
|
||||||
public DataManager Data { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="SeStringManager">SeStringManager</see> instance which allows creating and parsing SeString payloads.
|
|
||||||
/// </summary>
|
|
||||||
public SeStringManager SeStringManager { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether Dalamud is running in Debug mode or the /xldev menu is open. This can occur on release builds.
|
/// Gets a value indicating whether Dalamud is running in Debug mode or the /xldev menu is open. This can occur on release builds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -162,11 +127,6 @@ namespace Dalamud.Plugin
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public XivChatType GeneralChatType { get; private set; }
|
public XivChatType GeneralChatType { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the action that should be executed when any plugin sends a message.
|
|
||||||
/// </summary>
|
|
||||||
internal Action<string, ExpandoObject> AnyPluginIpcAction { get; private set; }
|
|
||||||
|
|
||||||
#region Configuration
|
#region Configuration
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -253,107 +213,6 @@ namespace Dalamud.Plugin
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IPC
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Subscribe to an IPC message by any plugin.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">The action to take when a message was received.</param>
|
|
||||||
[Obsolete("The current IPC mechanism is obsolete and scheduled to be replaced after API level 3.")]
|
|
||||||
public void SubscribeAny(Action<string, ExpandoObject> action)
|
|
||||||
{
|
|
||||||
if (this.AnyPluginIpcAction != null)
|
|
||||||
throw new InvalidOperationException("Can't subscribe multiple times.");
|
|
||||||
|
|
||||||
this.AnyPluginIpcAction = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Subscribe to an IPC message by a plugin.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pluginName">The InternalName of the plugin to subscribe to.</param>
|
|
||||||
/// <param name="action">The action to take when a message was received.</param>
|
|
||||||
[Obsolete("The current IPC mechanism is obsolete and scheduled to be replaced after API level 3.")]
|
|
||||||
public void Subscribe(string pluginName, Action<ExpandoObject> action)
|
|
||||||
{
|
|
||||||
var pluginManager = Service<PluginManager>.Get();
|
|
||||||
|
|
||||||
if (pluginManager.IpcSubscriptions.Any(x => x.SourcePluginName == this.pluginName && x.SubPluginName == pluginName))
|
|
||||||
throw new InvalidOperationException("Can't add multiple subscriptions for the same plugin.");
|
|
||||||
|
|
||||||
pluginManager.IpcSubscriptions.Add(new(this.pluginName, pluginName, action));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unsubscribe from messages from any plugin.
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("The current IPC mechanism is obsolete and scheduled to be replaced after API level 3.")]
|
|
||||||
public void UnsubscribeAny()
|
|
||||||
{
|
|
||||||
if (this.AnyPluginIpcAction == null)
|
|
||||||
throw new InvalidOperationException("Wasn't subscribed to this plugin.");
|
|
||||||
|
|
||||||
this.AnyPluginIpcAction = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unsubscribe from messages from a plugin.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pluginName">The InternalName of the plugin to unsubscribe from.</param>
|
|
||||||
[Obsolete("The current IPC mechanism is obsolete and scheduled to be replaced after API level 3.")]
|
|
||||||
public void Unsubscribe(string pluginName)
|
|
||||||
{
|
|
||||||
var pluginManager = Service<PluginManager>.Get();
|
|
||||||
|
|
||||||
var sub = pluginManager.IpcSubscriptions.FirstOrDefault(x => x.SourcePluginName == this.pluginName && x.SubPluginName == pluginName);
|
|
||||||
if (sub.SubAction == null)
|
|
||||||
throw new InvalidOperationException("Wasn't subscribed to this plugin.");
|
|
||||||
|
|
||||||
pluginManager.IpcSubscriptions.Remove(sub);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Send a message to all subscribed plugins.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message">The message to send.</param>
|
|
||||||
[Obsolete("The current IPC mechanism is obsolete and scheduled to be replaced after API level 3.")]
|
|
||||||
public void SendMessage(ExpandoObject message)
|
|
||||||
{
|
|
||||||
var pluginManager = Service<PluginManager>.Get();
|
|
||||||
|
|
||||||
var subs = pluginManager.IpcSubscriptions.Where(x => x.SubPluginName == this.pluginName);
|
|
||||||
foreach (var sub in subs.Select(x => x.SubAction))
|
|
||||||
{
|
|
||||||
sub.Invoke(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Send a message to a specific plugin.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pluginName">The InternalName of the plugin to send the message to.</param>
|
|
||||||
/// <param name="message">The message to send.</param>
|
|
||||||
/// <returns>True if the corresponding plugin was present and received the message.</returns>
|
|
||||||
[Obsolete("The current IPC mechanism is obsolete and scheduled to be replaced after API level 3.")]
|
|
||||||
public bool SendMessage(string pluginName, ExpandoObject message)
|
|
||||||
{
|
|
||||||
var pluginManager = Service<PluginManager>.Get();
|
|
||||||
|
|
||||||
var plugin = pluginManager.InstalledPlugins.FirstOrDefault(x => x.Manifest.InternalName == pluginName);
|
|
||||||
|
|
||||||
if (plugin == default)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (plugin.DalamudInterface?.AnyPluginIpcAction == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
plugin.DalamudInterface.AnyPluginIpcAction.Invoke(this.pluginName, message);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unregister your plugin and dispose all references. You have to call this when your IDalamudPlugin is disposed.
|
/// Unregister your plugin and dispose all references. You have to call this when your IDalamudPlugin is disposed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,5 @@ namespace Dalamud.Plugin
|
||||||
/// Gets the name of the plugin.
|
/// Gets the name of the plugin.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Name { get; }
|
string Name { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a Dalamud plugin.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pluginInterface">The <see cref="DalamudPluginInterface"/> needed to access various Dalamud objects.</param>
|
|
||||||
void Initialize(DalamudPluginInterface pluginInterface);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System.Reflection;
|
||||||
|
|
||||||
using Dalamud.Configuration.Internal;
|
using Dalamud.Configuration.Internal;
|
||||||
using Dalamud.Game;
|
using Dalamud.Game;
|
||||||
|
using Dalamud.IoC.Internal;
|
||||||
using Dalamud.Logging.Internal;
|
using Dalamud.Logging.Internal;
|
||||||
using Dalamud.Plugin.Internal.Exceptions;
|
using Dalamud.Plugin.Internal.Exceptions;
|
||||||
using Dalamud.Plugin.Internal.Types;
|
using Dalamud.Plugin.Internal.Types;
|
||||||
|
|
@ -26,15 +27,15 @@ namespace Dalamud.Plugin.Internal
|
||||||
|
|
||||||
private PluginLoader loader;
|
private PluginLoader loader;
|
||||||
private Assembly pluginAssembly;
|
private Assembly pluginAssembly;
|
||||||
private Type pluginType;
|
private Type? pluginType;
|
||||||
private IDalamudPlugin instance;
|
private IDalamudPlugin? instance;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="LocalPlugin"/> class.
|
/// Initializes a new instance of the <see cref="LocalPlugin"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dllFile">Path to the DLL file.</param>
|
/// <param name="dllFile">Path to the DLL file.</param>
|
||||||
/// <param name="manifest">The plugin manifest.</param>
|
/// <param name="manifest">The plugin manifest.</param>
|
||||||
public LocalPlugin(FileInfo dllFile, LocalPluginManifest?manifest)
|
public LocalPlugin(FileInfo dllFile, LocalPluginManifest? manifest)
|
||||||
{
|
{
|
||||||
this.DllFile = dllFile;
|
this.DllFile = dllFile;
|
||||||
this.State = PluginState.Unloaded;
|
this.State = PluginState.Unloaded;
|
||||||
|
|
@ -264,8 +265,16 @@ namespace Dalamud.Plugin.Internal
|
||||||
// Update the location for the Location and CodeBase patches
|
// Update the location for the Location and CodeBase patches
|
||||||
PluginManager.PluginLocations[this.pluginType.Assembly.FullName] = new(this.DllFile);
|
PluginManager.PluginLocations[this.pluginType.Assembly.FullName] = new(this.DllFile);
|
||||||
|
|
||||||
// Instantiate and initialize
|
this.DalamudInterface = new DalamudPluginInterface(this.pluginAssembly.GetName().Name!, reason);
|
||||||
this.instance = Activator.CreateInstance(this.pluginType) as IDalamudPlugin;
|
|
||||||
|
var ioc = Service<ServiceContainer>.Get();
|
||||||
|
this.instance = ioc.Create(this.pluginType, this.DalamudInterface) as IDalamudPlugin;
|
||||||
|
if (this.instance == null)
|
||||||
|
{
|
||||||
|
this.State = PluginState.LoadError;
|
||||||
|
Log.Error($"Error while loading {this.Name}, failed to bind and call the plugin constructor");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// In-case the manifest name was a placeholder. Can occur when no manifest was included.
|
// In-case the manifest name was a placeholder. Can occur when no manifest was included.
|
||||||
if (this.instance.Name != this.Manifest.Name)
|
if (this.instance.Name != this.Manifest.Name)
|
||||||
|
|
@ -274,30 +283,6 @@ namespace Dalamud.Plugin.Internal
|
||||||
this.Manifest.Save(this.manifestFile);
|
this.Manifest.Save(this.manifestFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.DalamudInterface = new DalamudPluginInterface(this.pluginAssembly.GetName().Name, reason);
|
|
||||||
|
|
||||||
if (this.IsDev)
|
|
||||||
{
|
|
||||||
// Inherit LPL's AssemblyLocation functionality
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
|
||||||
|
|
||||||
this.instance.GetType()
|
|
||||||
?.GetProperty("AssemblyLocation", bindingFlags)
|
|
||||||
?.SetValue(this.instance, this.DllFile.FullName);
|
|
||||||
this.instance.GetType()
|
|
||||||
?.GetMethod("SetLocation", bindingFlags)
|
|
||||||
?.Invoke(this.instance, new object[] { this.DllFile.FullName });
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.instance.Initialize(this.DalamudInterface);
|
|
||||||
|
|
||||||
this.State = PluginState.Loaded;
|
this.State = PluginState.Loaded;
|
||||||
Log.Information($"Finished loading {this.DllFile.Name}");
|
Log.Information($"Finished loading {this.DllFile.Name}");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue