feat: add ReadComponent and ReadSingleton methods

Introduce read-only access methods that return copies of components
to avoid unnecessary modification marking during iteration.
This commit is contained in:
hypercross 2026-07-18 21:24:03 +08:00
parent f1eddc75ae
commit 910fd00a03
1 changed files with 26 additions and 5 deletions

View File

@ -251,14 +251,14 @@ public class World : IDisposable
_changes.Pending.MarkComponentRemoved(entity, typeof(T)); _changes.Pending.MarkComponentRemoved(entity, typeof(T));
} }
/// <summary>
/// <summary> /// <summary>
/// Returns a reference to the component of type <typeparamref name="T"/> /// Returns a reference to the component of type <typeparamref name="T"/>
/// for the given entity. Throws if the entity does not have the component. /// for the given entity. Throws if the entity does not have the component.
/// ///
/// During iteration (inside <see cref="ForEach"/> or a <c>Select</c> loop), /// During iteration, this access is auto-marked as modified since it
/// components accessed through this method are automatically marked as /// returns a mutable ref. Use <see cref="ReadComponent{T}"/> if you
/// modified when the iteration scope ends. Outside of iteration, /// only need to read the value.
/// <see cref="MarkModified{T}"/> must be called explicitly.
/// </summary> /// </summary>
public ref T GetComponent<T>(Entity entity) where T : struct public ref T GetComponent<T>(Entity entity) where T : struct
{ {
@ -267,10 +267,21 @@ public class World : IDisposable
return ref _components.Get<T>(entity); return ref _components.Get<T>(entity);
} }
/// <summary>
/// Returns a copy of the component of type <typeparamref name="T"/>
/// for the given entity. Never auto-marks as modified — use this when
/// you only need to read the value.
/// </summary>
public T ReadComponent<T>(Entity entity) where T : struct
{
return _components.Get<T>(entity);
}
/// <summary> /// <summary>
/// Tries to get the component of type <typeparamref name="T"/> for the /// Tries to get the component of type <typeparamref name="T"/> for the
/// given entity. Returns true and copies the value to /// given entity. Returns true and copies the value to
/// <paramref name="value"/> if the component exists; otherwise returns false. /// <paramref name="value"/> if the component exists; otherwise returns false.
/// Never auto-marks as modified.
/// </summary> /// </summary>
public bool TryGetComponent<T>(Entity entity, out T value) where T : struct public bool TryGetComponent<T>(Entity entity, out T value) where T : struct
{ {
@ -352,7 +363,7 @@ public class World : IDisposable
/// <summary> /// <summary>
/// Returns a reference to the singleton component of type <typeparamref name="T"/>. /// Returns a reference to the singleton component of type <typeparamref name="T"/>.
/// Throws if the singleton has not been set. /// Throws if the singleton has not been set. Auto-marks as modified during iteration.
/// </summary> /// </summary>
public ref T GetSingleton<T>() where T : struct public ref T GetSingleton<T>() where T : struct
{ {
@ -360,6 +371,16 @@ public class World : IDisposable
return ref GetComponent<T>(SingletonEntity); return ref GetComponent<T>(SingletonEntity);
} }
/// <summary>
/// Returns a copy of the singleton component of type <typeparamref name="T"/>.
/// Never auto-marks as modified — use this when you only need to read the singleton.
/// </summary>
public T ReadSingleton<T>() where T : struct
{
EnsureSingleton();
return ReadComponent<T>(SingletonEntity);
}
/// <summary> /// <summary>
/// Returns true if a singleton component of type <typeparamref name="T"/> exists. /// Returns true if a singleton component of type <typeparamref name="T"/> exists.
/// </summary> /// </summary>