perf: cache hash code in QueryDescriptor

fix: notify change buffer when removing components in World

docs: add caution about structural changes during ForEach

fix: prevent multiple disposals in World
This commit is contained in:
hypercross 2026-07-18 20:13:25 +08:00
parent 6f9efc050b
commit dddddbdbd6
2 changed files with 18 additions and 1 deletions

View File

@ -17,10 +17,13 @@ public class QueryDescriptor
/// </summary>
public IReadOnlySet<Type> Without { get; }
private readonly int _hashCode;
internal QueryDescriptor(HashSet<Type> with, HashSet<Type> without)
{
With = with;
Without = without;
_hashCode = ComputeHashCode();
}
/// <summary>
@ -36,7 +39,9 @@ public class QueryDescriptor
return With.SetEquals(other.With) && Without.SetEquals(other.Without);
}
public override int GetHashCode()
public override int GetHashCode() => _hashCode;
private int ComputeHashCode()
{
var hash = new HashCode();
foreach (var t in With.OrderBy(t => t.GUID.ToString()))

View File

@ -22,6 +22,7 @@ public class World : IDisposable
private readonly RelationshipIndex _relationships;
private readonly ChangeBuffer _changes;
private bool _singletonCreated;
private bool _disposed;
#if DEBUG
// Tracks entities whose components were accessed via GetComponent<T>
@ -82,6 +83,7 @@ public class World : IDisposable
{
_relationships.OnRemoved(relType, source, entity);
_components.Remove(source, relType);
_changes.Pending.MarkComponentRemoved(source, relType);
}
}
@ -358,6 +360,13 @@ public class World : IDisposable
/// <summary>
/// Iterates all entities matching the query, providing ref access to
/// one component type.
///
/// <b>Caution:</b> Adding or removing components (including destroying
/// entities) during iteration may cause entities to be skipped or
/// processed twice. This is a consequence of the sparse set's
/// swap-remove strategy. If you need to make structural changes,
/// collect the affected entities first, then apply changes after
/// the iteration.
/// </summary>
public void ForEach<T1>(
QueryDescriptor query,
@ -486,6 +495,9 @@ public class World : IDisposable
public void Dispose()
{
if (_disposed)
return;
_disposed = true;
_changes.Dispose();
}