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);
}
}
}