using System.Collections; using System.Collections.Generic; namespace Rokid.UXR.Interaction { /// /// A registry that houses a set of concrete Interactables. /// 包含一组具体可交互对象的注册表。 /// public class InteractableRegistry where TInteractor : Interactor where TInteractable : Interactable { /// /// Allocation-free collection that can be iterated over /// to provide a pruned list of Interactables. /// public struct InteractableSet : IEnumerable { private readonly IReadOnlyList _data; private readonly ISet _onlyInclude; private readonly TInteractor _testAgainst; /// /// A pruned set of interactables from the /// /// /// Include only these interactables from /// the base collection. /// Provide a null value to skip this filtering. /// Filter against an interactor. /// Provide a null value to skip this filtering. public InteractableSet( ISet onlyInclude, TInteractor testAgainst) { _data = _interactables; _onlyInclude = onlyInclude; _testAgainst = testAgainst; } public Enumerator GetEnumerator() { return new Enumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private bool Include(TInteractable interactable) { // Skip interactables not contained in a provided subset if (_onlyInclude != null) { if (!_onlyInclude.Contains(interactable)) { return false; } } // Skip interactables that fail test against interactable if (_testAgainst != null) { if (!_testAgainst.CanSelect(interactable)) { return false; } if (!interactable.CanBeSelectedBy(_testAgainst)) { return false; } } return true; } public struct Enumerator : IEnumerator { private readonly InteractableSet _set; private int _position; private IReadOnlyList Data => _set._data; public Enumerator(in InteractableSet set) { _set = set; _position = -1; } public TInteractable Current { get { if (Data == null || _position < 0) { throw new System.InvalidOperationException(); } return Data[_position]; } } object IEnumerator.Current => Current; public bool MoveNext() { if (Data == null) { return false; } do { _position++; } while (_position < Data.Count && !_set.Include(Data[_position])); return _position < Data.Count; } public void Reset() { _position = -1; } public void Dispose() { } } } private static List _interactables; public InteractableRegistry() { _interactables = new List(); } public virtual void Register(TInteractable interactable) { _interactables.Add(interactable); } public virtual void Unregister(TInteractable interactable) { _interactables.Remove(interactable); } /// /// Returns a filtered collection of interactables /// /// Only interactables that can be selected by /// this interactor will be returned /// Only interactables included in this /// subset will be included in the returned collection protected InteractableSet List(TInteractor interactor, HashSet onlyInclude) { return new InteractableSet(onlyInclude, interactor); } /// /// Returns a filtered collection of interactables /// /// Only interactables that can be selected by /// this interactor will be returned public virtual InteractableSet List(TInteractor interactor) { return new InteractableSet(null, interactor); } /// /// Returns all interactables in this registry /// public virtual InteractableSet List() { return new InteractableSet(null, null); } } }