Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions src/Godot.Bindings/Core/GodotObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ partial class GodotObject : IDisposable
internal nint NativePtr;
private readonly GCHandle _gcHandle;

private readonly WeakReference<GodotObject>? _weakReferenceToSelf;
private readonly WeakReference<RefCounted>? _weakReferenceToSelf;

private bool _disposed;

Expand Down Expand Up @@ -206,10 +206,7 @@ protected unsafe virtual void Dispose(bool disposing)
NativePtr = 0;
}

if (_weakReferenceToSelf is not null)
{
DisposablesTracker.UnregisterGodotObject(this, _weakReferenceToSelf);
}
DisposablesTracker.UnregisterGodotObject(this, _weakReferenceToSelf);
}

/// <summary>
Expand Down
31 changes: 22 additions & 9 deletions src/Godot.Bindings/NativeInterop/DisposablesTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ namespace Godot.NativeInterop;

internal static class DisposablesTracker
{
private static readonly ConcurrentDictionary<WeakReference<GodotObject>, byte> _godotObjectInstances =
private static readonly ConcurrentDictionary<GodotObject, byte> _godotObjectInstances =
new();

private static readonly ConcurrentDictionary<WeakReference<RefCounted>, byte> _refCountedInstances =
new();

private static readonly ConcurrentDictionary<WeakReference<IDisposable>, byte> _otherInstances =
new();

Expand All @@ -25,9 +28,14 @@ internal static void DisposeAll()
// like StringName, NodePath, GodotArray/GodotDictionary, etc.
// The GodotObject Dispose() method may need any of the later instances.

foreach (WeakReference<GodotObject> item in _godotObjectInstances.Keys)
foreach (GodotObject self in _godotObjectInstances.Keys)
{
self.Dispose();
}

foreach (WeakReference<RefCounted> item in _refCountedInstances.Keys)
{
if (item.TryGetTarget(out GodotObject? self))
if (item.TryGetTarget(out RefCounted? self))
{
self.Dispose();
}
Expand All @@ -47,11 +55,16 @@ internal static void DisposeAll()
}
}

public static WeakReference<GodotObject> RegisterGodotObject(GodotObject godotObject)
public static WeakReference<RefCounted>? RegisterGodotObject(GodotObject godotObject)
{
var weakReferenceToSelf = new WeakReference<GodotObject>(godotObject);
_godotObjectInstances.TryAdd(weakReferenceToSelf, 0);
return weakReferenceToSelf;
if (godotObject is RefCounted rc)
{
var weakReferenceToSelf = new WeakReference<RefCounted>(rc);
_refCountedInstances.TryAdd(weakReferenceToSelf, 0);
return weakReferenceToSelf;
}
_godotObjectInstances.TryAdd(godotObject, 0);
return null;
}

public static WeakReference<IDisposable> RegisterDisposable(IDisposable disposable)
Expand All @@ -63,9 +76,9 @@ public static WeakReference<IDisposable> RegisterDisposable(IDisposable disposab
return weakReferenceToSelf;
}

public static void UnregisterGodotObject(GodotObject godotObject, WeakReference<GodotObject> weakReferenceToSelf)
public static void UnregisterGodotObject(GodotObject godotObject, WeakReference<RefCounted>? weakReferenceToSelf)
{
if (!_godotObjectInstances.TryRemove(weakReferenceToSelf, out _))
if (godotObject is RefCounted rc ? !_refCountedInstances.TryRemove(weakReferenceToSelf!, out _) : !_godotObjectInstances.TryRemove(godotObject, out _))
{
throw new ArgumentException("Godot Object not registered.", nameof(weakReferenceToSelf));
}
Expand Down