Skip to content

Commit

Permalink
fix DebugWindow Asset tracking memory leak
Browse files Browse the repository at this point in the history
  • Loading branch information
lodicolo committed Feb 2, 2025
1 parent 1232308 commit 66eaff9
Showing 1 changed file with 60 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@
using Intersect.Client.Framework.Gwen.Control;
using Intersect.Client.Framework.Gwen.Control.Utility;
using Intersect.Client.Localization;
using Intersect.Core;
using Intersect.Framework.Reflection;
using Microsoft.Extensions.Logging;

namespace Intersect.Client.Interface.Debugging;

public sealed class TexturesSearchableTreeDataProvider : ISearchableTreeDataProvider
{
private readonly GameContentManager _contentManager;
private readonly Dictionary<string, SearchableTreeDataEntry> _entries;
private readonly Dictionary<IAsset, ContentType> _contentTypeByAsset;
private readonly Dictionary<string, Dictionary<string, SearchableTreeDataEntry>> _entriesByParent;
private readonly Base _parent;

Expand All @@ -20,6 +24,22 @@ public TexturesSearchableTreeDataProvider(GameContentManager contentManager, Bas
_contentManager = contentManager;
_parent = parent;

var allContent = _contentManager.Content.ToArray();
_contentTypeByAsset = allContent.SelectMany(
pair =>
{
var (contentType, contentTypeAssets) = pair;
return contentTypeAssets.Select(asset => new KeyValuePair<IAsset, ContentType>(asset, contentType));
}
).ToDictionary();

foreach (var (asset, _) in _contentTypeByAsset)
{
asset.Disposed += OnAssetStateChanged;
asset.Loaded += OnAssetStateChanged;
asset.Unloaded += OnAssetStateChanged;
}

_entries = _contentManager.Content.SelectMany(
contentTypeEntry =>
{
Expand All @@ -30,15 +50,15 @@ public TexturesSearchableTreeDataProvider(GameContentManager contentManager, Bas
contentTypeName = contentType.ToString();
}

var assets = contentTypeEntry.Value.ToArray();
SearchableTreeDataEntry[] entriesForTextureType =
[
new(
Id: contentTypeId,
DisplayText: contentTypeName,
DisplayColor: parent.Skin.Colors.Label.Default
),
..contentTypeEntry.Value.OfType<GameTexture>()
.Select(texture => EntryForAsset(contentTypeId, texture)),
..assets.Select(asset => EntryForAsset(contentTypeId, asset)),
];

return entriesForTextureType;
Expand All @@ -54,6 +74,43 @@ public TexturesSearchableTreeDataProvider(GameContentManager contentManager, Bas
);
}

private void OnAssetStateChanged(IAsset changedAsset)
{
if (!_contentTypeByAsset.TryGetValue(changedAsset, out var contentType))
{
ApplicationContext.Context.Value?.Logger.LogWarning(
"Asset {AssetType} '{AssetId}' not indexed, unable to get content type",
changedAsset.GetType().GetName(qualified: true),
changedAsset.Id
);
return;
}

var contentTypeId = $"{nameof(ContentType)}:{contentType}";
var updatedEntry = EntryForAsset(contentTypeId, changedAsset);
_entries[updatedEntry.Id] = updatedEntry;
var ancestorIds = GetAncestorIds(updatedEntry.ParentId);

foreach (var ancestorId in ancestorIds)
{
if (!_entriesByParent.TryGetValue(ancestorId, out var entriesForAncestor))
{
entriesForAncestor = [];
_entriesByParent[ancestorId] = entriesForAncestor;
}

entriesForAncestor[updatedEntry.Id] = updatedEntry;
}

EntriesChanged?.Invoke(
_parent,
new SearchableTreeDataEntriesEventArgs
{
Entries = [updatedEntry],
}
);
}

private string[] GetAncestorIds(string? firstAncestorId)
{
if (string.IsNullOrWhiteSpace(firstAncestorId))
Expand All @@ -80,7 +137,7 @@ private string[] GetAncestorIds(string? firstAncestorId)
return ancestorIds.ToArray();
}

private SearchableTreeDataEntry EntryForAsset(string parentId, IAsset asset)
private static SearchableTreeDataEntry EntryForAsset(string parentId, IAsset asset)
{
Color displayColor = Color.Green;
if (asset.IsDisposed)
Expand All @@ -92,10 +149,6 @@ private SearchableTreeDataEntry EntryForAsset(string parentId, IAsset asset)
displayColor = Color.White;
}

asset.Disposed += OnAssetStateChanged;
asset.Loaded += OnAssetStateChanged;
asset.Unloaded += OnAssetStateChanged;

var assetName = asset.Name ?? asset.Id;

var displayText = assetName;
Expand All @@ -112,32 +165,6 @@ private SearchableTreeDataEntry EntryForAsset(string parentId, IAsset asset)
ParentId: parentId,
UserData: asset
);

void OnAssetStateChanged(IAsset changedAsset)
{
var updatedEntry = EntryForAsset(parentId, changedAsset);
_entries[updatedEntry.Id] = updatedEntry;
var ancestorIds = GetAncestorIds(updatedEntry.ParentId);

foreach (var ancestorId in ancestorIds)
{
if (!_entriesByParent.TryGetValue(ancestorId, out var entriesForAncestor))
{
entriesForAncestor = [];
_entriesByParent[ancestorId] = entriesForAncestor;
}

entriesForAncestor[updatedEntry.Id] = updatedEntry;
}

EntriesChanged?.Invoke(
_parent,
new SearchableTreeDataEntriesEventArgs
{
Entries = [updatedEntry],
}
);
}
}

public event Base.GwenEventHandler<SearchableTreeDataEntriesEventArgs>? EntriesAdded;
Expand Down

0 comments on commit 66eaff9

Please sign in to comment.