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; } }