forked from Shardstone/trail-into-darkness
added zlinq
This commit is contained in:
248
Packages/ZLinq.Unity/Runtime/GameObjectTraverser.cs
Normal file
248
Packages/ZLinq.Unity/Runtime/GameObjectTraverser.cs
Normal file
@@ -0,0 +1,248 @@
|
||||
#nullable enable
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
using ZLinq.Traversables;
|
||||
|
||||
namespace ZLinq
|
||||
{
|
||||
public static class GameObjectTraverserExtensions
|
||||
{
|
||||
public static GameObjectTraverser AsTraverser(this GameObject origin) => new(origin);
|
||||
|
||||
// type inference helper
|
||||
|
||||
public static ValueEnumerable<Children<GameObjectTraverser, GameObject>, GameObject> Children(this GameObjectTraverser traverser) => traverser.Children<GameObjectTraverser, GameObject>();
|
||||
public static ValueEnumerable<Children<GameObjectTraverser, GameObject>, GameObject> ChildrenAndSelf(this GameObjectTraverser traverser) => traverser.ChildrenAndSelf<GameObjectTraverser, GameObject>();
|
||||
public static ValueEnumerable<Descendants<GameObjectTraverser, GameObject>, GameObject> Descendants(this GameObjectTraverser traverser) => traverser.Descendants<GameObjectTraverser, GameObject>();
|
||||
public static ValueEnumerable<Descendants<GameObjectTraverser, GameObject>, GameObject> DescendantsAndSelf(this GameObjectTraverser traverser) => traverser.DescendantsAndSelf<GameObjectTraverser, GameObject>();
|
||||
public static ValueEnumerable<Ancestors<GameObjectTraverser, GameObject>, GameObject> Ancestors(this GameObjectTraverser traverser) => traverser.Ancestors<GameObjectTraverser, GameObject>();
|
||||
public static ValueEnumerable<Ancestors<GameObjectTraverser, GameObject>, GameObject> AncestorsAndSelf(this GameObjectTraverser traverser) => traverser.AncestorsAndSelf<GameObjectTraverser, GameObject>();
|
||||
public static ValueEnumerable<BeforeSelf<GameObjectTraverser, GameObject>, GameObject> BeforeSelf(this GameObjectTraverser traverser) => traverser.BeforeSelf<GameObjectTraverser, GameObject>();
|
||||
public static ValueEnumerable<BeforeSelf<GameObjectTraverser, GameObject>, GameObject> BeforeSelfAndSelf(this GameObjectTraverser traverser) => traverser.BeforeSelfAndSelf<GameObjectTraverser, GameObject>();
|
||||
public static ValueEnumerable<AfterSelf<GameObjectTraverser, GameObject>, GameObject> AfterSelf(this GameObjectTraverser traverser) => traverser.AfterSelf<GameObjectTraverser, GameObject>();
|
||||
public static ValueEnumerable<AfterSelf<GameObjectTraverser, GameObject>, GameObject> AfterSelfAndSelf(this GameObjectTraverser traverser) => traverser.AfterSelfAndSelf<GameObjectTraverser, GameObject>();
|
||||
|
||||
// direct shortcut
|
||||
|
||||
public static ValueEnumerable<Children<GameObjectTraverser, GameObject>, GameObject> Children(this GameObject origin) => origin.AsTraverser().Children();
|
||||
public static ValueEnumerable<Children<GameObjectTraverser, GameObject>, GameObject> ChildrenAndSelf(this GameObject origin) => origin.AsTraverser().ChildrenAndSelf();
|
||||
public static ValueEnumerable<Descendants<GameObjectTraverser, GameObject>, GameObject> Descendants(this GameObject origin) => origin.AsTraverser().Descendants();
|
||||
public static ValueEnumerable<Descendants<GameObjectTraverser, GameObject>, GameObject> DescendantsAndSelf(this GameObject origin) => origin.AsTraverser().DescendantsAndSelf();
|
||||
public static ValueEnumerable<Ancestors<GameObjectTraverser, GameObject>, GameObject> Ancestors(this GameObject origin) => origin.AsTraverser().Ancestors();
|
||||
public static ValueEnumerable<Ancestors<GameObjectTraverser, GameObject>, GameObject> AncestorsAndSelf(this GameObject origin) => origin.AsTraverser().AncestorsAndSelf();
|
||||
public static ValueEnumerable<BeforeSelf<GameObjectTraverser, GameObject>, GameObject> BeforeSelf(this GameObject origin) => origin.AsTraverser().BeforeSelf();
|
||||
public static ValueEnumerable<BeforeSelf<GameObjectTraverser, GameObject>, GameObject> BeforeSelfAndSelf(this GameObject origin) => origin.AsTraverser().BeforeSelfAndSelf();
|
||||
public static ValueEnumerable<AfterSelf<GameObjectTraverser, GameObject>, GameObject> AfterSelf(this GameObject origin) => origin.AsTraverser().AfterSelf();
|
||||
public static ValueEnumerable<AfterSelf<GameObjectTraverser, GameObject>, GameObject> AfterSelfAndSelf(this GameObject origin) => origin.AsTraverser().AfterSelfAndSelf();
|
||||
|
||||
// OfComponent
|
||||
|
||||
public static ValueEnumerable<OfComponentG<Children<GameObjectTraverser, GameObject>, TComponent>, TComponent> OfComponent<TComponent>(this ValueEnumerable<Children<GameObjectTraverser, GameObject>, GameObject> source)
|
||||
where TComponent : Component => new(new(source.Enumerator));
|
||||
|
||||
public static ValueEnumerable<OfComponentG<Descendants<GameObjectTraverser, GameObject>, TComponent>, TComponent> OfComponent<TComponent>(this ValueEnumerable<Descendants<GameObjectTraverser, GameObject>, GameObject> source)
|
||||
where TComponent : Component => new(new(source.Enumerator));
|
||||
|
||||
public static ValueEnumerable<OfComponentG<Ancestors<GameObjectTraverser, GameObject>, TComponent>, TComponent> OfComponent<TComponent>(this ValueEnumerable<Ancestors<GameObjectTraverser, GameObject>, GameObject> source)
|
||||
where TComponent : Component => new(new(source.Enumerator));
|
||||
|
||||
public static ValueEnumerable<OfComponentG<BeforeSelf<GameObjectTraverser, GameObject>, TComponent>, TComponent> OfComponent<TComponent>(this ValueEnumerable<BeforeSelf<GameObjectTraverser, GameObject>, GameObject> source)
|
||||
where TComponent : Component => new(new(source.Enumerator));
|
||||
|
||||
public static ValueEnumerable<OfComponentG<AfterSelf<GameObjectTraverser, GameObject>, TComponent>, TComponent> OfComponent<TComponent>(this ValueEnumerable<AfterSelf<GameObjectTraverser, GameObject>, GameObject> source)
|
||||
where TComponent : Component => new(new(source.Enumerator));
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct GameObjectTraverser : ITraverser<GameObjectTraverser, GameObject>
|
||||
{
|
||||
static readonly object CalledTryGetNextChild = new object();
|
||||
static readonly object ParentNotFound = new object();
|
||||
|
||||
readonly GameObject gameObject;
|
||||
readonly Transform transform; // cache transform
|
||||
object? initializedState; // CalledTryGetNext or Parent(for sibling operations)
|
||||
int childCount; // self childCount(TryGetNextChild) or parent childCount(TryGetSibling)
|
||||
int index;
|
||||
|
||||
public GameObjectTraverser(GameObject origin)
|
||||
{
|
||||
this.gameObject = origin;
|
||||
this.transform = gameObject.transform;
|
||||
this.initializedState = null;
|
||||
this.childCount = 0;
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
public GameObject Origin => gameObject;
|
||||
public GameObjectTraverser ConvertToTraverser(GameObject next) => new(next);
|
||||
|
||||
public bool TryGetParent(out GameObject parent)
|
||||
{
|
||||
var tp = transform.parent;
|
||||
if (tp != null)
|
||||
{
|
||||
parent = tp.gameObject;
|
||||
return true;
|
||||
}
|
||||
|
||||
parent = default!;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetChildCount(out int count)
|
||||
{
|
||||
count = transform.childCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetHasChild(out bool hasChild)
|
||||
{
|
||||
hasChild = transform.childCount != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetNextChild(out GameObject child)
|
||||
{
|
||||
if (initializedState == null)
|
||||
{
|
||||
initializedState = CalledTryGetNextChild;
|
||||
childCount = transform.childCount;
|
||||
}
|
||||
|
||||
if (index < childCount)
|
||||
{
|
||||
child = transform.GetChild(index++).gameObject;
|
||||
return true;
|
||||
}
|
||||
|
||||
child = default!;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetNextSibling(out GameObject next)
|
||||
{
|
||||
if (initializedState == null)
|
||||
{
|
||||
var tp = transform.parent;
|
||||
if (tp == null)
|
||||
{
|
||||
var scene = transform.gameObject.scene;
|
||||
// check is scene root object
|
||||
if (scene.IsValid())
|
||||
{
|
||||
initializedState = scene;
|
||||
childCount = scene.rootCount;
|
||||
index = transform.GetSiblingIndex() + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
initializedState = ParentNotFound;
|
||||
next = default!;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// cache parent and childCount
|
||||
initializedState = tp;
|
||||
childCount = tp.childCount; // parent's childCount
|
||||
index = transform.GetSiblingIndex() + 1;
|
||||
}
|
||||
}
|
||||
else if (initializedState == ParentNotFound)
|
||||
{
|
||||
next = default!;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (initializedState is Transform parent)
|
||||
{
|
||||
if (index < childCount)
|
||||
{
|
||||
next = parent.GetChild(index++).gameObject;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (initializedState is UnityEngine.SceneManagement.Scene scene)
|
||||
{
|
||||
if (index < childCount)
|
||||
{
|
||||
var list = UnityEngine.Pool.ListPool<GameObject>.Get();
|
||||
scene.GetRootGameObjects(list);
|
||||
next = list[index++];
|
||||
UnityEngine.Pool.ListPool<GameObject>.Release(list);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
next = default!;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetPreviousSibling(out GameObject previous)
|
||||
{
|
||||
if (initializedState == null)
|
||||
{
|
||||
var tp = transform.parent;
|
||||
if (tp == null)
|
||||
{
|
||||
var scene = transform.gameObject.scene;
|
||||
// check is scene root object
|
||||
if (scene.IsValid())
|
||||
{
|
||||
initializedState = scene;
|
||||
childCount = transform.GetSiblingIndex();
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
initializedState = ParentNotFound;
|
||||
previous = default!;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
initializedState = tp;
|
||||
childCount = transform.GetSiblingIndex(); // not childCount but means `to`
|
||||
index = 0; // 0 to siblingIndex
|
||||
}
|
||||
}
|
||||
else if (initializedState == ParentNotFound)
|
||||
{
|
||||
previous = default!;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (initializedState is Transform parent)
|
||||
{
|
||||
if (index < childCount)
|
||||
{
|
||||
previous = parent.GetChild(index++).gameObject;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (initializedState is UnityEngine.SceneManagement.Scene scene)
|
||||
{
|
||||
if (index < childCount)
|
||||
{
|
||||
var list = UnityEngine.Pool.ListPool<GameObject>.Get();
|
||||
scene.GetRootGameObjects(list);
|
||||
previous = list[index++];
|
||||
UnityEngine.Pool.ListPool<GameObject>.Release(list);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
previous = default!;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user