using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Cysharp.Threading.Tasks;
using Speckle.ConnectorUnity.Converter;
using Speckle.Core.Kits;
using Speckle.Core.Logging;
using Speckle.Core.Models;
using UnityEngine;
namespace Speckle.ConnectorUnity.Models
{
///
/// A speckle node is pretty much the reference object that is first pulled from a commit
///
[AddComponentMenu(SpeckleUnity.NAMESPACE + "/Node")]
public class SpeckleNode : MonoBehaviour
{
[SerializeField] [HideInInspector] string id;
[SerializeField] [HideInInspector] string appId;
[SerializeField] [HideInInspector] long childCount;
[SerializeField] SpeckleObjectHierarchy hierarchy;
///
/// Reference object id
///
public string Id => id;
///
/// Reference to application ID
///
public string AppId => appId;
///
/// Total child count
///
public long ChildCount => childCount;
public List GetObjects() => hierarchy.GetObjects();
public void AddLayer(SpeckleLayer layer) => hierarchy.Add(layer);
///
/// Setup the hierarchy for the commit coming in
///
/// The object to convert
/// Speckle Converter to parse objects with
/// Cancellation token
///
public async UniTask DataToScene(Base data, ISpeckleConverter converter, CancellationToken token)
{
if (data == null) return;
id = data.id;
appId = data.applicationId;
childCount = (int)data.totalChildrenCount;
name = $"Node: {id}";
if (converter == null)
{
SpeckleUnity.Console.Warn("No valid converter to use during conversion ");
return;
}
hierarchy = new SpeckleObjectHierarchy();
var defaultLayer = new GameObject("Default").AddComponent();
DeconstructObject(data, defaultLayer, converter, token);
Debug.Log("Speckle Node Complete");
if (defaultLayer.Layers.Any())
{
defaultLayer.SetObjectParent(transform);
hierarchy.Add(defaultLayer);
}
else
SpeckleUnity.SafeDestroy(defaultLayer.gameObject);
if (converter is ScriptableSpeckleConverter sc)
{
Debug.Log("Doing post work");
await sc.PostWork();
}
}
void DeconstructObject(Base data, SpeckleLayer defaultLayer, ISpeckleConverter converter, CancellationToken token)
{
if (token.IsCancellationRequested) return;
// 1: Object is supported, so lets convert the object and it's data
if (converter.CanConvertToNative(data))
{
// NOTE: Object created in scene
// NOTE: This is where the game object instance could be captured and meta stored in each object
// NOTE: The converter should spawn a series of mono objects that will handle going through the list of objects to convert and send data to
var obj = CheckConvertedFormat(converter.ConvertToNative(data));
if (obj != null)
defaultLayer.Add(obj);
}
// 2: Check for the properties of an object. There might be additional objects that we want to convert as well
foreach (var member in data.GetMemberNames())
{
if (token.IsCancellationRequested)
return;
// NOTE: we should only have to check for certain props and make sure to not duplicate any
var obj = data[member];
// 2a: A prop is a list! We create a special list object to store those items in
if (obj.IsList())
{
// create the list container
var layer = ListToLayer(member, ((IEnumerable)obj).Cast