#nullable enable using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Speckle.ConnectorUnity.NativeCache; using Speckle.Core.Models; using Speckle.Core.Models.GraphTraversal; using UnityEngine; namespace Speckle.ConnectorUnity.Components { public partial class RecursiveConverter { public IEnumerator ConvertToNative(Base rootObject, Transform? parent, IDictionary outCreatedObjects) { InitializeAssetCache(); var traversalFunc = DefaultTraversal.CreateBIMTraverseFunc(ConverterInstance); var convertableObjects = traversalFunc.Traverse(rootObject) .Where(tc => ConverterInstance.CanConvertToNative(tc.current)); foreach (TraversalContext tc in convertableObjects) { Transform? nativeParent = parent; if (tc.parent != null && outCreatedObjects.TryGetValue(tc.parent.current, out GameObject p)) nativeParent = p.transform; GameObject? go = ConverterInstance.ConvertToNative(tc.current) as GameObject; if (go == null) continue; go.transform.SetParent(parent, true); outCreatedObjects.Add(tc.current, go); //Set some common for all created GameObjects //TODO add support for more unity specific props if(go.name == "New Game Object" || string.IsNullOrWhiteSpace(go.name)) go.name = AssetHelpers.GenerateObjectName(tc.current); //if (baseObject["tag"] is string t) go.tag = t; if (tc.current["physicsLayer"] is string layerName) { int layer = LayerMask.NameToLayer(layerName); //TODO: check how this can be interoperable with Unreal and Blender if (layer > -1) go.layer = layer; } //if (baseObject["isStatic"] is bool isStatic) go.isStatic = isStatic; yield return go; } } public IEnumerator ConvertCoroutine(Base rootObject, Transform? parent, List outCreatedObjects) => ConvertCoroutine(rootObject, parent, outCreatedObjects,b => ConverterInstance.CanConvertToNative(b)); public IEnumerator ConvertCoroutine(Base rootObject, Transform? parent, List outCreatedObjects, Func predicate) { foreach (string propertyName in GetPotentialChildren(rootObject)) { ConvertChild(rootObject[propertyName], parent, predicate, outCreatedObjects); yield return null; } } /// /// Given , /// will recursively convert any objects in the tree /// /// The object to convert ( or of) /// Optional parent transform for the created root s /// A list of all created s public virtual List RecursivelyConvertToNative(object? o, Transform? parent) => RecursivelyConvertToNative(o, parent, b => ConverterInstance.CanConvertToNative(b)); /// /// A function to determine if an object should be converted public virtual List RecursivelyConvertToNative(object? o, Transform? parent, Func predicate) { InitializeAssetCache(); var createdGameObjects = new List(); try { AssetCache.BeginWrite(); ConvertChild(o, parent, predicate, createdGameObjects); } finally { AssetCache.FinishWrite(); } //TODO track event? return createdGameObjects; } private void InitializeAssetCache() { //Ensure we have A native cache if (AssetCache.nativeCaches.Any(x => x == null)) { AssetCache.nativeCaches = NativeCacheFactory.GetStandaloneCacheSetup(); } ConverterInstance.SetContextDocument(AssetCache); } public virtual void RecurseTreeToNative(Base baseObject, Transform? parent, Func predicate, IList outCreatedObjects) { object? converted = null; if(predicate(baseObject)) converted = ConverterInstance.ConvertToNative(baseObject); // Handle new GameObjects Transform? nextParent = parent; if (converted is GameObject go) { outCreatedObjects.Add(go); nextParent = go.transform; go.transform.SetParent(parent, true); //Set some common for all created GameObjects //TODO add support for more unity specific props if(go.name == "New Game Object" || string.IsNullOrWhiteSpace(go.name)) go.name = AssetHelpers.GenerateObjectName(baseObject); //if (baseObject["tag"] is string t) go.tag = t; if (baseObject["physicsLayer"] is string layerName) { int layer = LayerMask.NameToLayer(layerName); //TODO: check how this can be interoperable with Unreal and Blender if (layer > -1) go.layer = layer; } //if (baseObject["isStatic"] is bool isStatic) go.isStatic = isStatic; } // For geometry, only traverse `elements` prop, otherwise, try and convert everything IEnumerable potentialChildren = GetPotentialChildren(baseObject); // Convert Children foreach (string propertyName in potentialChildren) { ConvertChild(baseObject[propertyName], nextParent, predicate, outCreatedObjects); } } private IEnumerable GetPotentialChildren(Base baseObject) { return ConverterInstance.CanConvertToNative(baseObject) ? new []{"elements"} : baseObject.GetMembers().Keys; } protected virtual void ConvertChild(object? value, Transform? parent, Func predicate, IList outCreatedObjects) { foreach (Base b in GraphTraversal.TraverseMember(value)) { RecurseTreeToNative(b, parent, predicate, outCreatedObjects); } } [Obsolete("Use " + nameof(RecursivelyConvertToNative), true)] public GameObject ConvertRecursivelyToNative(Base @base, string name) { var parentObject = new GameObject(name); RecursivelyConvertToNative(@base, parentObject.transform); return parentObject; } } }