using Robust.Client.Graphics;
namespace Content.Client.Graphics;
///
/// A cache for s to store per-viewport render resources, such as render targets.
///
/// The type of data stored in the cache.
public sealed class OverlayResourceCache : IDisposable where T : class, IDisposable
{
private readonly Dictionary _cache = new();
///
/// Get the data for a specific viewport, creating a new entry if necessary.
///
///
/// The cached data may be cleared at any time if gets invoked.
///
/// The viewport for which to retrieve cached data.
/// A delegate used to create the cached data, if necessary.
public T GetForViewport(IClydeViewport viewport, Func factory)
{
return GetForViewport(viewport, out _, factory);
}
///
/// Get the data for a specific viewport, creating a new entry if necessary.
///
///
/// The cached data may be cleared at any time if gets invoked.
///
/// The viewport for which to retrieve cached data.
/// True if the data was pulled from cache, false if it was created anew.
/// A delegate used to create the cached data, if necessary.
public T GetForViewport(IClydeViewport viewport, out bool wasCached, Func factory)
{
if (_cache.TryGetValue(viewport.Id, out var entry))
{
wasCached = true;
return entry.Data;
}
wasCached = false;
entry = new CacheEntry
{
Data = factory(viewport),
Viewport = new WeakReference(viewport),
};
_cache.Add(viewport.Id, entry);
viewport.ClearCachedResources += ViewportOnClearCachedResources;
return entry.Data;
}
private void ViewportOnClearCachedResources(ClearCachedViewportResourcesEvent ev)
{
if (!_cache.Remove(ev.ViewportId, out var entry))
{
// I think this could theoretically happen if you manually dispose the cache *after* a leaked viewport got
// GC'd, but before its ClearCachedResources got invoked.
return;
}
entry.Data.Dispose();
if (ev.Viewport != null)
ev.Viewport.ClearCachedResources -= ViewportOnClearCachedResources;
}
public void Dispose()
{
foreach (var entry in _cache)
{
if (entry.Value.Viewport.TryGetTarget(out var viewport))
viewport.ClearCachedResources -= ViewportOnClearCachedResources;
entry.Value.Data.Dispose();
}
_cache.Clear();
}
private struct CacheEntry
{
public T Data;
public WeakReference Viewport;
}
}