feat: implement auto-dirty-marking for query iterators
Introduce `TrackAccess` in `World` to record component access during batching scopes. Update `SelectN` iterators to provide `RefN` for mutable, tracked access and `ValN` for read-only, untracked access.
This commit is contained in:
@@ -275,6 +275,17 @@ public class World : IDisposable
|
||||
return ref _components.Get<T>(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tracks a component access for auto-dirty-marking without returning
|
||||
/// a ref. Used by <see cref="SelectN"/> iterators when they expose
|
||||
/// component refs directly from the sparse set.
|
||||
/// </summary>
|
||||
internal void TrackAccess(Entity entity, Type componentType)
|
||||
{
|
||||
if (_batchingDepth > 0)
|
||||
_accessedComponents.Add((entity, componentType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of the component of type <typeparamref name="T"/>
|
||||
/// for the given entity. Never auto-marks as modified — use this when
|
||||
|
||||
@@ -126,8 +126,25 @@ public ref struct Select1<T1> where T1 : struct
|
||||
/// <summary>The current enumerator (required for foreach duck-typing).</summary>
|
||||
public Select1<T1> Current => this;
|
||||
|
||||
/// <summary>Read-write reference to the current entity's component of type <typeparamref name="T1"/>.</summary>
|
||||
public ref T1 Item1 => ref _set!.Get(Entity);
|
||||
/// <summary>
|
||||
/// Mutable reference to the current entity's component of type <typeparamref name="T1"/>.
|
||||
/// Access is tracked for auto-dirty-marking during a batching scope.
|
||||
/// </summary>
|
||||
public ref T1 Ref1
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get
|
||||
{
|
||||
_world.TrackAccess(Entity, typeof(T1));
|
||||
return ref _set!.Get(Entity);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read-only reference to the current entity's component of type <typeparamref name="T1"/>.
|
||||
/// Access is NOT tracked for auto-dirty-marking.
|
||||
/// </summary>
|
||||
public ref readonly T1 Val1 => ref _set!.Get(Entity);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
@@ -193,8 +210,29 @@ public ref struct Select2<T1, T2> where T1 : struct where T2 : struct
|
||||
|
||||
public Entity Entity { get; private set; }
|
||||
public Select2<T1, T2> Current => this;
|
||||
public ref T1 Item1 => ref _set1!.Get(Entity);
|
||||
public ref T2 Item2 => ref _set2!.Get(Entity);
|
||||
|
||||
public ref T1 Ref1
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get
|
||||
{
|
||||
_world.TrackAccess(Entity, typeof(T1));
|
||||
return ref _set1!.Get(Entity);
|
||||
}
|
||||
}
|
||||
|
||||
public ref T2 Ref2
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get
|
||||
{
|
||||
_world.TrackAccess(Entity, typeof(T2));
|
||||
return ref _set2!.Get(Entity);
|
||||
}
|
||||
}
|
||||
|
||||
public ref readonly T1 Val1 => ref _set1!.Get(Entity);
|
||||
public ref readonly T2 Val2 => ref _set2!.Get(Entity);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
@@ -273,9 +311,14 @@ public ref struct Select3<T1, T2, T3>
|
||||
|
||||
public Entity Entity { get; private set; }
|
||||
public Select3<T1, T2, T3> Current => this;
|
||||
public ref T1 Item1 => ref _set1!.Get(Entity);
|
||||
public ref T2 Item2 => ref _set2!.Get(Entity);
|
||||
public ref T3 Item3 => ref _set3!.Get(Entity);
|
||||
|
||||
public ref T1 Ref1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T1)); return ref _set1!.Get(Entity); } }
|
||||
public ref T2 Ref2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T2)); return ref _set2!.Get(Entity); } }
|
||||
public ref T3 Ref3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T3)); return ref _set3!.Get(Entity); } }
|
||||
|
||||
public ref readonly T1 Val1 => ref _set1!.Get(Entity);
|
||||
public ref readonly T2 Val2 => ref _set2!.Get(Entity);
|
||||
public ref readonly T3 Val3 => ref _set3!.Get(Entity);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
@@ -365,10 +408,16 @@ public ref struct Select4<T1, T2, T3, T4>
|
||||
|
||||
public Entity Entity { get; private set; }
|
||||
public Select4<T1, T2, T3, T4> Current => this;
|
||||
public ref T1 Item1 => ref _set1!.Get(Entity);
|
||||
public ref T2 Item2 => ref _set2!.Get(Entity);
|
||||
public ref T3 Item3 => ref _set3!.Get(Entity);
|
||||
public ref T4 Item4 => ref _set4!.Get(Entity);
|
||||
|
||||
public ref T1 Ref1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T1)); return ref _set1!.Get(Entity); } }
|
||||
public ref T2 Ref2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T2)); return ref _set2!.Get(Entity); } }
|
||||
public ref T3 Ref3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T3)); return ref _set3!.Get(Entity); } }
|
||||
public ref T4 Ref4 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T4)); return ref _set4!.Get(Entity); } }
|
||||
|
||||
public ref readonly T1 Val1 => ref _set1!.Get(Entity);
|
||||
public ref readonly T2 Val2 => ref _set2!.Get(Entity);
|
||||
public ref readonly T3 Val3 => ref _set3!.Get(Entity);
|
||||
public ref readonly T4 Val4 => ref _set4!.Get(Entity);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
@@ -471,11 +520,18 @@ public ref struct Select5<T1, T2, T3, T4, T5>
|
||||
|
||||
public Entity Entity { get; private set; }
|
||||
public Select5<T1, T2, T3, T4, T5> Current => this;
|
||||
public ref T1 Item1 => ref _set1!.Get(Entity);
|
||||
public ref T2 Item2 => ref _set2!.Get(Entity);
|
||||
public ref T3 Item3 => ref _set3!.Get(Entity);
|
||||
public ref T4 Item4 => ref _set4!.Get(Entity);
|
||||
public ref T5 Item5 => ref _set5!.Get(Entity);
|
||||
|
||||
public ref T1 Ref1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T1)); return ref _set1!.Get(Entity); } }
|
||||
public ref T2 Ref2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T2)); return ref _set2!.Get(Entity); } }
|
||||
public ref T3 Ref3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T3)); return ref _set3!.Get(Entity); } }
|
||||
public ref T4 Ref4 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T4)); return ref _set4!.Get(Entity); } }
|
||||
public ref T5 Ref5 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T5)); return ref _set5!.Get(Entity); } }
|
||||
|
||||
public ref readonly T1 Val1 => ref _set1!.Get(Entity);
|
||||
public ref readonly T2 Val2 => ref _set2!.Get(Entity);
|
||||
public ref readonly T3 Val3 => ref _set3!.Get(Entity);
|
||||
public ref readonly T4 Val4 => ref _set4!.Get(Entity);
|
||||
public ref readonly T5 Val5 => ref _set5!.Get(Entity);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
@@ -593,12 +649,20 @@ public ref struct Select6<T1, T2, T3, T4, T5, T6>
|
||||
|
||||
public Entity Entity { get; private set; }
|
||||
public Select6<T1, T2, T3, T4, T5, T6> Current => this;
|
||||
public ref T1 Item1 => ref _set1!.Get(Entity);
|
||||
public ref T2 Item2 => ref _set2!.Get(Entity);
|
||||
public ref T3 Item3 => ref _set3!.Get(Entity);
|
||||
public ref T4 Item4 => ref _set4!.Get(Entity);
|
||||
public ref T5 Item5 => ref _set5!.Get(Entity);
|
||||
public ref T6 Item6 => ref _set6!.Get(Entity);
|
||||
|
||||
public ref T1 Ref1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T1)); return ref _set1!.Get(Entity); } }
|
||||
public ref T2 Ref2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T2)); return ref _set2!.Get(Entity); } }
|
||||
public ref T3 Ref3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T3)); return ref _set3!.Get(Entity); } }
|
||||
public ref T4 Ref4 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T4)); return ref _set4!.Get(Entity); } }
|
||||
public ref T5 Ref5 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T5)); return ref _set5!.Get(Entity); } }
|
||||
public ref T6 Ref6 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T6)); return ref _set6!.Get(Entity); } }
|
||||
|
||||
public ref readonly T1 Val1 => ref _set1!.Get(Entity);
|
||||
public ref readonly T2 Val2 => ref _set2!.Get(Entity);
|
||||
public ref readonly T3 Val3 => ref _set3!.Get(Entity);
|
||||
public ref readonly T4 Val4 => ref _set4!.Get(Entity);
|
||||
public ref readonly T5 Val5 => ref _set5!.Get(Entity);
|
||||
public ref readonly T6 Val6 => ref _set6!.Get(Entity);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
@@ -679,4 +743,4 @@ public ref struct Select6<T1, T2, T3, T4, T5, T6>
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user