diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs index 47a973c66..a435e24d7 100644 --- a/Dalamud/Dalamud.cs +++ b/Dalamud/Dalamud.cs @@ -17,6 +17,7 @@ using Dalamud.Game.Text.SeStringHandling; using Dalamud.Hooking.Internal; using Dalamud.Interface.Internal; using Dalamud.IoC.Internal; +using Dalamud.Plugin; using Dalamud.Plugin.Internal; using Serilog; using Serilog.Core; @@ -237,6 +238,8 @@ namespace Dalamud { try { + Service.Set(); + var pluginManager = Service.Set(); pluginManager.OnInstalledPluginsChanged += () => Troubleshooting.LogTroubleshooting(); diff --git a/Dalamud/Interface/Internal/Windows/DataWindow.cs b/Dalamud/Interface/Internal/Windows/DataWindow.cs index 8fb88ef8a..f515773cb 100644 --- a/Dalamud/Interface/Internal/Windows/DataWindow.cs +++ b/Dalamud/Interface/Internal/Windows/DataWindow.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Dynamic; using System.Linq; using System.Numerics; @@ -26,7 +25,6 @@ using Dalamud.Game.Text; using Dalamud.Interface.Windowing; using Dalamud.Memory; using Dalamud.Plugin; -using Dalamud.Plugin.Internal; using Dalamud.Utility; using ImGuiNET; using ImGuiScene; @@ -62,6 +60,11 @@ namespace Dalamud.Interface.Internal.Windows private UIDebug addonInspector = null; + // IPC + private ICallGatePub ipcPub; + private ICallGateSub ipcSub; + private string callGateResponse = string.Empty; + // Toast fields private string inputTextToast = string.Empty; private int toastPosition = 0; @@ -610,6 +613,56 @@ namespace Dalamud.Interface.Internal.Windows private void DrawPluginIPC() { + if (this.ipcPub == null) + { + this.ipcPub = Service.Get().GetIpcPubSub("dataDemo1"); + + this.ipcPub.RegisterAction((msg) => + { + Log.Information($"Data action was called: {msg}"); + }); + + this.ipcPub.RegisterFunc((msg) => + { + Log.Information($"Data func was called: {msg}"); + return Guid.NewGuid().ToString(); + }); + } + + if (this.ipcSub == null) + { + this.ipcSub = Service.Get().GetIpcPubSub("dataDemo1"); + this.ipcSub.Subscribe((msg) => + { + Log.Information("PONG1"); + }); + this.ipcSub.Subscribe((msg) => + { + Log.Information("PONG2"); + }); + this.ipcSub.Subscribe((msg) => + { + throw new Exception("PONG3"); + }); + } + + if (ImGui.Button("PING")) + { + this.ipcPub.SendMessage("PING"); + } + + if (ImGui.Button("Action")) + { + this.ipcSub.InvokeAction("button1"); + } + + if (ImGui.Button("Func")) + { + this.callGateResponse = this.ipcSub.InvokeFunc("button2"); + } + + if (!this.callGateResponse.IsNullOrEmpty()) + ImGui.Text($"Response: {this.callGateResponse}"); } private void DrawCondition() diff --git a/Dalamud/Plugin/CallGate.cs b/Dalamud/Plugin/CallGate.cs new file mode 100644 index 000000000..9a643308c --- /dev/null +++ b/Dalamud/Plugin/CallGate.cs @@ -0,0 +1,770 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Serilog; + +#pragma warning disable SA1201 // Elements should appear in the correct order +#pragma warning disable SA1402 // File may only contain a single type + +namespace Dalamud.Plugin +{ + /// + /// This class facilitates inter-plugin communication. + /// + internal class CallGate + { + private Dictionary gates = new(); + + #region GetIpcPubSub + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(TRet)); + + #endregion + + /// + /// Gets or sets an IPC pub/sub callgate. + /// + /// Name of the IPC registration. + /// The callgate parameter types. + /// The IPC pub/sub callgate. + private CallGateBase GetIpcPubSub(string name, params Type[] types) + { + if (!this.gates.TryGetValue(name, out var callGate)) + { + var generic = types.Length switch + { + 1 => typeof(CallGatePubSub<>), + 2 => typeof(CallGatePubSub<,>), + 3 => typeof(CallGatePubSub<,,>), + 4 => typeof(CallGatePubSub<,,,>), + 5 => typeof(CallGatePubSub<,,,,>), + 6 => typeof(CallGatePubSub<,,,,,>), + 7 => typeof(CallGatePubSub<,,,,,,>), + 8 => typeof(CallGatePubSub<,,,,,,,>), + 9 => typeof(CallGatePubSub<,,,,,,,,>), + _ => throw new Exception("Misconfigured number of type args"), + }; + + var type = generic.MakeGenericType(types); + callGate = (CallGateBase)Activator.CreateInstance(type); + callGate.Name = name; + + this.gates[name] = callGate; + } + + var requested = callGate.GetType().GenericTypeArguments; + if (!Enumerable.SequenceEqual(requested, types)) + throw new IpcTypeMismatchError(name, requested, types); + + return callGate; + } + } + + #region ICallGatePub + + /// + public interface ICallGatePub + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(); + } + + /// + public interface ICallGatePub + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1); + } + + /// + public interface ICallGatePub + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1, T2 arg2); + } + + /// + public interface ICallGatePub + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3); + } + + /// + public interface ICallGatePub + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + } + + /// + public interface ICallGatePub + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + } + + /// + public interface ICallGatePub + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); + } + + /// + public interface ICallGatePub + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + } + + /// + public interface ICallGatePub + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); + } + + #endregion + + #region ICallGateSub + + /// + public interface ICallGateSub + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(); + + /// + public TRet InvokeFunc(); + } + + /// + public interface ICallGateSub + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1); + + /// + public TRet InvokeFunc(T1 arg1); + } + + /// + public interface ICallGateSub + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1, T2 arg2); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2); + } + + /// + public interface ICallGateSub + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3); + } + + /// + public interface ICallGateSub + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + } + + /// + public interface ICallGateSub + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + } + + /// + public interface ICallGateSub + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); + } + + /// + public interface ICallGateSub + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + } + + /// + public interface ICallGateSub + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); + } + + #endregion + + #region CallGatePubSub + + /// + internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage() + => base.SendMessage(); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction() + => base.InvokeAction(); + + /// + public TRet InvokeFunc() + => (TRet)base.InvokeFunc(); + } + + /// + internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1) + => base.SendMessage(arg1); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1) + => base.InvokeAction(arg1); + + /// + public TRet InvokeFunc(T1 arg1) + => (TRet)base.InvokeFunc(arg1); + } + + /// + internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1, T2 arg2) + => base.SendMessage(arg1, arg2); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1, T2 arg2) + => base.InvokeAction(arg1, arg2); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2) + => (TRet)base.InvokeFunc(arg1, arg2); + } + + /// + internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3) + => base.SendMessage(arg1, arg2, arg3); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3) + => base.InvokeAction(arg1, arg2, arg3); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3) + => (TRet)base.InvokeFunc(arg1, arg2, arg3); + } + + /// + internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4) + => base.SendMessage(arg1, arg2, arg3, arg4); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4) + => base.InvokeAction(arg1, arg2, arg3, arg4); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4) + => (TRet)base.InvokeFunc(arg1, arg2, arg3, arg4); + } + + /// + internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + => base.SendMessage(arg1, arg2, arg3, arg4, arg5); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + => base.InvokeAction(arg1, arg2, arg3, arg4, arg5); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + => (TRet)base.InvokeFunc(arg1, arg2, arg3, arg4, arg5); + } + + /// + internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + => base.SendMessage(arg1, arg2, arg3, arg4, arg5, arg6); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + => base.InvokeAction(arg1, arg2, arg3, arg4, arg5, arg6); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + => (TRet)base.InvokeFunc(arg1, arg2, arg3, arg4, arg5, arg6); + } + + /// + internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + => base.SendMessage(arg1, arg2, arg3, arg4, arg5, arg6, arg7); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + => base.InvokeAction(arg1, arg2, arg3, arg4, arg5, arg6, arg7); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + => (TRet)base.InvokeFunc(arg1, arg2, arg3, arg4, arg5, arg6, arg7); + } + + /// + internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + => base.SendMessage(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + => base.InvokeAction(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + => (TRet)base.InvokeFunc(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + } + + #endregion + + /// + /// This class facilitates inter-plugin communication. + /// + internal class CallGateBase + { + /// + /// Initializes a new instance of the class. + /// + internal CallGateBase() + { + } + + /// + /// Gets or sets the name of the IPC registration. + /// + public string Name { get; internal set; } + + /// + /// Gets or sets the Action. + /// + protected Delegate? Action { get; set; } + + /// + /// Gets or sets the Func. + /// + protected Delegate? Func { get; set; } + + /// + /// Gets the list of subscribed delegates. + /// + protected List Subs { get; } = new(); + + /// + /// Removes a registered Action from inter-plugin communication. + /// + public void UnregisterAction() + => this.Action = null; + + /// + /// Removes a registered Func from inter-plugin communication. + /// + public void UnregisterFunc() + => this.Func = null; + + /// + /// Removes a registered Action from inter-plugin communication. + /// + /// Action to register. + private protected void RegisterAction(Delegate action) + => this.Action = action; + + /// + /// Removes a registered Func from inter-plugin communication. + /// + /// Func to register. + private protected void RegisterFunc(Delegate func) + => this.Func = func; + + /// + /// Invoke all actions that have subscribed to this IPC. + /// + /// Delegate arguments. + private protected void SendMessage(params object?[]? args) + { + foreach (var sub in this.Subs) + { + try + { + sub.DynamicInvoke(args); + } + catch (Exception ex) + { + Log.Error(ex, $"Error invoking a subscription of {this.Name}"); + } + } + } + + /// + /// Subscribe an expression to this registration. + /// + /// Action to subscribe. + private protected void Subscribe(Delegate action) + => this.Subs.Add(action); + + /// + /// Unsubscribe an expression from this registration. + /// + /// Action to unsubscribe. + private protected void Unsubscribe(Delegate action) + => this.Subs.Remove(action); + + /// + /// Invoke an action registered for inter-plugin communication. + /// + /// Action arguments. + /// This is thrown when the IPC publisher has not registered an action for calling yet. + private protected void InvokeAction(params object?[]? args) + => (this.Action ?? throw new IpcNotReadyError(this.Name)).DynamicInvoke(args); + + /// + /// Invoke a function registered for inter-plugin communication. + /// + /// Parameter args. + /// The return value. + /// This is thrown when the IPC publisher has not registered a func for calling yet. + private protected object InvokeFunc(params object?[]? args) + => (this.Func ?? throw new IpcNotReadyError(this.Name)).DynamicInvoke(args); + } +} + +#pragma warning restore SA1402 // File may only contain a single type +#pragma warning restore SA1201 // Elements should appear in the correct order diff --git a/Dalamud/Plugin/DalamudPluginInterface.cs b/Dalamud/Plugin/DalamudPluginInterface.cs index f8793a4dc..d81b1a84c 100644 --- a/Dalamud/Plugin/DalamudPluginInterface.cs +++ b/Dalamud/Plugin/DalamudPluginInterface.cs @@ -134,6 +134,93 @@ namespace Dalamud.Plugin /// public List PluginInternalNames => Service.Get().InstalledPlugins.Select(p => p.Manifest.InternalName).ToList(); + #region IPC + + /// + /// Gets an IPC publisher. + /// + /// The return type for funcs. Use object if this is unused. + /// The name of the IPC registration. + /// An IPC publisher. + /// This is thrown when the requested types do not match the previously registered types are different. + public ICallGatePub GetIpcPub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGatePub GetIpcPub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGatePub GetIpcPub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGatePub GetIpcPub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGatePub GetIpcPub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGatePub GetIpcPub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGatePub GetIpcPub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGatePub GetIpcPub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGatePub GetIpcPub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + /// Gets an IPC subscriber. + /// + /// The return type for funcs. Use object if this is unused. + /// The name of the IPC registration. + /// An IPC publisher. + public ICallGateSub GetIpcSub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGateSub GetIpcSub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGateSub GetIpcSub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGateSub GetIpcSub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGateSub GetIpcSub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGateSub GetIpcSub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGateSub GetIpcSub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGateSub GetIpcSub(string name) + => Service.Get().GetIpcPubSub(name); + + /// + public ICallGateSub GetIpcSub(string name) + => Service.Get().GetIpcPubSub(name); + + #endregion + #region Configuration /// diff --git a/Dalamud/Plugin/IpcNotReadyError.cs b/Dalamud/Plugin/IpcNotReadyError.cs new file mode 100644 index 000000000..8be24d577 --- /dev/null +++ b/Dalamud/Plugin/IpcNotReadyError.cs @@ -0,0 +1,27 @@ +using System; + +namespace Dalamud.Plugin +{ + /// + /// This exception is thrown when an IPC method is invoked, but nothing has been registered by that name yet. + /// + public class IpcNotReadyError : Exception + { + /// + /// Initializes a new instance of the class. + /// + /// Name of the IPC method. + public IpcNotReadyError(string name) + { + this.Name = name; + } + + /// + /// Gets the name of the IPC that was invoked. + /// + public string Name { get; } + + /// + public override string Message => $"IPC method {this.Name} was not registered yet"; + } +} diff --git a/Dalamud/Plugin/IpcTypeMismatchError.cs b/Dalamud/Plugin/IpcTypeMismatchError.cs new file mode 100644 index 000000000..5a73507b7 --- /dev/null +++ b/Dalamud/Plugin/IpcTypeMismatchError.cs @@ -0,0 +1,48 @@ +using System; +using System.Linq; + +namespace Dalamud.Plugin +{ + /// + /// This exception is thrown when an IPC method is checked out, but the type does not match what was previously registered. + /// + public class IpcTypeMismatchError : Exception + { + private readonly string message; + + /// + /// Initializes a new instance of the class. + /// + /// Name of the IPC method. + /// The types requested when checking out the IPC. + /// The types registered by the IPC. + public IpcTypeMismatchError(string name, Type[] requestedTypes, Type[] actualTypes) + { + this.Name = name; + this.RequestedTypes = requestedTypes; + this.ActualTypes = actualTypes; + + var t1 = string.Join(", ", this.RequestedTypes.Select(t => t.Name)); + var t2 = string.Join(", ", this.ActualTypes.Select(t => t.Name)); + this.message = $"IPC method {this.Name} has a different type than was requested. [ {t1} ] != [ {t2} ]"; + } + + /// + /// Gets the name of the IPC that was invoked. + /// + public string Name { get; } + + /// + /// Gets the types that were requested. + /// + public Type[] RequestedTypes { get; } + + /// + /// Gets the types that were previously registered. + /// + public Type[] ActualTypes { get; } + + /// + public override string Message => this.message; + } +}