using AssetRipper.Assets.Collections; using AssetRipper.Assets.Generics; using AssetRipper.SourceGenerated.Classes.ClassID_1; using AssetRipper.SourceGenerated.Classes.ClassID_1001; using AssetRipper.SourceGenerated.Classes.ClassID_18; using AssetRipper.SourceGenerated.Classes.ClassID_2; using AssetRipper.SourceGenerated.Classes.ClassID_4; using AssetRipper.SourceGenerated.Classes.ClassID_78; using AssetRipper.SourceGenerated.Enums; using AssetRipper.SourceGenerated.Subclasses.ComponentPair; using AssetRipper.SourceGenerated.Subclasses.PPtr_Component; namespace AssetRipper.SourceGenerated.Extensions { public static class GameObjectExtensions { /// /// Less than 4.0.0 /// private static bool IsActiveInherited(UnityVersion version) => version.LessThan(4); public static bool GetIsActive(this IGameObject gameObject) { return gameObject.IsActive_Boolean || gameObject.IsActive_Byte > 0; } public static void SetIsActive(this IGameObject gameObject, bool active) { gameObject.IsActive_Byte = active ? (byte)1 : (byte)0; gameObject.IsActive_Boolean = active; } private static bool ShouldBeActive(this IGameObject gameObject) { if (IsActiveInherited(gameObject.Collection.Version) && !gameObject.Collection.IsScene) { return true; } return gameObject.GetIsActive(); } public static void ConvertToEditorFormat(this IGameObject gameObject, ITagManager? tagManager) { gameObject.SetIsActive(gameObject.ShouldBeActive()); gameObject.TagString = tagManager.TagIDToName(gameObject.Tag); } public static IEnumerable FetchComponents(this IGameObject gameObject) { return gameObject.Components.Select(pair => pair.Component); } public static AccessListBase GetComponentPPtrList(this IGameObject gameObject) { return new ComponentPairAccessList(gameObject.Components); } public static int GetComponentCount(this IGameObject gameObject) { return gameObject.Components.Count; } public static void AddComponent(this IGameObject gameObject, ClassIDType classID, IComponent component) { IComponentPair pair = gameObject.Components.AddNew(); pair.ClassID = (int)classID; pair.Component.SetAsset(gameObject.Collection, component); } public static PPtrAccessList GetComponentAccessList(this IGameObject gameObject) { return new PPtrAccessList(gameObject.GetComponentPPtrList(), gameObject.Collection); } public static T? TryGetComponent(this IGameObject gameObject) where T : IComponent { gameObject.TryGetComponent(out T? component); return component; } public static bool TryGetComponent(this IGameObject gameObject, [NotNullWhen(true)] out T? component) where T : IComponent { foreach (IComponent? comp in gameObject.GetComponentAccessList()) { // component could have not implemented asset type if (comp is T t) { component = t; return true; } } component = default; return false; } public static T GetComponent(this IGameObject gameObject) where T : IComponent { if (!gameObject.TryGetComponent(out T? component)) { throw new Exception($"Component of type {typeof(T)} hasn't been found"); } return component; } public static ITransform GetTransform(this IGameObject gameObject) { foreach (IComponent? component in gameObject.GetComponentAccessList()) { if (component is ITransform transform) { return transform; } } throw new Exception("Can't find transform component"); } public static bool IsRoot(this IGameObject gameObject) { return gameObject.TryGetComponent()?.Father_C4P is null; } public static IGameObject GetRoot(this IGameObject gameObject) { if (!gameObject.TryGetComponent(out ITransform? root)) { return gameObject; } while (true) { ITransform? parent = root.Father_C4P; if (parent is null || parent.GameObject_C4P is null) { break; } else { root = parent; } } return root.GameObject_C4P!; } public static int GetRootDepth(this IGameObject gameObject) { if (!gameObject.TryGetComponent(out ITransform? root)) { return 0; } int depth = 0; while (true) { ITransform? parent = root.Father_C4P; if (parent == null) { break; } root = parent; depth++; } return depth; } /// /// Fetch all the assets in the hierarchy for this . /// /// /// This includes the . /// /// /// /// A referenced asset wasn't found. public static IEnumerable FetchHierarchy(this IGameObject root) { yield return root; ITransform? transform = null; foreach (IComponent component in root.GetComponentAccessList().WhereNotNull()) { yield return component; if (component is ITransform trfm) { transform = trfm; } } if (transform is null) { yield break; } foreach (IGameObject child in transform.Children_C4P.WhereNotNull().Select(t => t.GameObject_C4P).WhereNotNull()) { foreach (IEditorExtension childElement in child.FetchHierarchy()) { yield return childElement; } } } public static IEnumerable GetChildren(this IGameObject gameObject) { ITransform transform = gameObject.GetTransform(); return transform.Children_C4P.WhereNotNull().Select(t => t.GameObject_C4P).WhereNotNull(); } public static IPrefabInstance CreatePrefabForRoot(this IGameObject root, ProcessedAssetCollection collection) { IPrefabInstance prefab = collection.CreateAsset((int)ClassIDType.PrefabInstance, PrefabInstance.Create); prefab.HideFlagsE = HideFlags.HideInHierarchy; prefab.RootGameObjectP = root; prefab.IsPrefabAsset = true; prefab.AssetBundleName = root.AssetBundleName; prefab.OriginalDirectory = root.OriginalDirectory; prefab.OriginalName = root.OriginalName; prefab.OriginalExtension = root.OriginalExtension; prefab.OverrideDirectory = root.GetBestDirectory(); prefab.OverrideName = root.GetBestName(); prefab.OverrideExtension = root.GetBestExtension(); prefab.SetPrefabInternal(); return prefab; } private sealed class ComponentPairAccessList : AccessListBase { private readonly AccessListBase referenceList; public ComponentPairAccessList(AccessListBase referenceList) { this.referenceList = referenceList; } public override IPPtr_Component this[int index] { get => referenceList[index].Component; set => throw new NotSupportedException(); } public override int Count => referenceList.Count; public override int Capacity { get => referenceList.Capacity; set => referenceList.Capacity = value; } public override void Add(IPPtr_Component item) { throw new NotSupportedException(); } public override IPPtr_Component AddNew() { IComponentPair componentPair = referenceList.AddNew(); componentPair.ClassID = (int)ClassIDType.Component; return componentPair.Component; //throw new NotSupportedException(); //Not sure the above code is safe since Unity might rely on the class id being correct. } public override void Clear() { referenceList.Clear(); } public override bool Contains(IPPtr_Component item) { return referenceList.Any(ptr => ptr.Component.Equals(item)); } public override void CopyTo(IPPtr_Component[] array, int arrayIndex) { for (int i = 0; i < referenceList.Count; i++) { array[i + arrayIndex] = referenceList[i].Component; } } public override int EnsureCapacity(int capacity) { return referenceList.EnsureCapacity(capacity); } public override int IndexOf(IPPtr_Component item) { return referenceList.IndexOf(pair => pair.Component.Equals(item)); } public override void Insert(int index, IPPtr_Component item) { throw new NotSupportedException(); } public override bool Remove(IPPtr_Component item) { int index = IndexOf(item); if (index < 0) { return false; } else { RemoveAt(index); return true; } } public override void RemoveAt(int index) { referenceList.RemoveAt(index); } } } }