diff --git a/Dalamud/Plugin/DalamudPluginInterface.cs b/Dalamud/Plugin/DalamudPluginInterface.cs
index 95b2e3e80..055b34cb1 100644
--- a/Dalamud/Plugin/DalamudPluginInterface.cs
+++ b/Dalamud/Plugin/DalamudPluginInterface.cs
@@ -175,21 +175,21 @@ namespace Dalamud.Plugin
#region IPC
- ///
+ ///
public T GetOrCreateData(string tag, Func dataGenerator) where T : class
- => Service.Get().GetOrCreateData(tag, dataGenerator);
+ => Service.Get().GetOrCreateData(tag, dataGenerator);
- ///
+ ///
public void RelinquishData(string tag)
- => Service.Get().RelinquishData(tag);
+ => Service.Get().RelinquishData(tag);
- ///
+ ///
public bool TryGetData(string tag, [NotNullWhen(true)] out T? data) where T : class
- => Service.Get().TryGetData(tag, out data);
+ => Service.Get().TryGetData(tag, out data);
- ///
+ ///
public T? GetData(string tag) where T : class
- => Service.Get().GetData(tag);
+ => Service.Get().GetData(tag);
///
/// Gets an IPC provider.
diff --git a/Dalamud/Plugin/Ipc/Internal/DataCache.cs b/Dalamud/Plugin/Ipc/Internal/DataCache.cs
index d404cbba2..c357f77c2 100644
--- a/Dalamud/Plugin/Ipc/Internal/DataCache.cs
+++ b/Dalamud/Plugin/Ipc/Internal/DataCache.cs
@@ -3,18 +3,34 @@ using System.Collections.Generic;
namespace Dalamud.Plugin.Ipc.Internal;
-internal class DataCache
+///
+/// A helper struct for reference-counted, type-safe shared access across plugin boundaries.
+///
+internal readonly struct DataCache
{
- internal readonly string CreatorAssemblyName;
- internal readonly List UserAssemblyNames;
- internal readonly Type Type;
- internal readonly object? Data;
+ /// The assembly name of the initial creator.
+ internal readonly string CreatorAssemblyName;
- internal DataCache(string creatorAssemblyName, object? data, Type type)
+ /// A not-necessarily distinct list of current users.
+ internal readonly List UserAssemblyNames;
+
+ /// The type the data was registered as.
+ internal readonly Type Type;
+
+ /// A reference to data.
+ internal readonly object? Data;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The assembly name of the initial creator.
+ /// A reference to data.
+ /// The type of the data.
+ public DataCache(string creatorAssemblyName, object? data, Type type)
{
this.CreatorAssemblyName = creatorAssemblyName;
- this.UserAssemblyNames = new List{ creatorAssemblyName };
- this.Data = data;
- this.Type = type;
+ this.UserAssemblyNames = new List { creatorAssemblyName };
+ this.Data = data;
+ this.Type = type;
}
}
diff --git a/Dalamud/Plugin/Ipc/Internal/DataShare.cs b/Dalamud/Plugin/Ipc/Internal/DataShare.cs
index f22d9848c..d0c080e28 100644
--- a/Dalamud/Plugin/Ipc/Internal/DataShare.cs
+++ b/Dalamud/Plugin/Ipc/Internal/DataShare.cs
@@ -2,10 +2,14 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
+
using Dalamud.Plugin.Ipc.Exceptions;
namespace Dalamud.Plugin.Ipc.Internal;
+///
+/// This class facilitates sharing data-references of standard types between plugins without using more expensive IPC.
+///
[ServiceManager.EarlyLoadedService]
internal class DataShare : IServiceType
{
@@ -45,7 +49,7 @@ internal class DataShare : IServiceType
if (obj == null)
throw new Exception("Returned data was null.");
- cache = new DataCache(callerName, obj, typeof(T));
+ cache = new DataCache(callerName, obj, typeof(T));
this.caches[tag] = cache;
return obj;
}
@@ -104,7 +108,23 @@ internal class DataShare : IServiceType
///
/// The type for the requested data - needs to be a reference type.
/// The name for the data cache.
- /// The requested data on success or null.
- public T? GetData(string tag) where T : class
- => TryGetData(tag, out var data) ? data : null;
+ /// The requested data
+ /// Thrown if is not registered.
+ /// Thrown if a cache for exists, but contains data of a type not assignable to .
+ /// Thrown if the stored data for a cache is null.
+ public T GetData(string tag) where T : class
+ {
+ if (!this.caches.TryGetValue(tag, out var cache))
+ throw new KeyNotFoundException($"The data cache {tag} is not registered.");
+
+ var callerName = Assembly.GetCallingAssembly().GetName().Name ?? string.Empty;
+ if (!cache.Type.IsAssignableTo(typeof(T)))
+ throw new DataCacheTypeMismatchError(tag, callerName, typeof(T), cache.Type);
+
+ if (cache.Data is not T data)
+ throw new DataCacheValueNullError(tag, typeof(T));
+
+ cache.UserAssemblyNames.Add(callerName);
+ return data;
+ }
}