reformat code
This commit is contained in:
Родитель
5d92e12eff
Коммит
aa46d49620
|
@ -2,11 +2,8 @@ using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using Speckle.ConnectorUnity;
|
using Speckle.ConnectorUnity;
|
||||||
using UnityEditor.Experimental;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
|
||||||
|
|
||||||
[RequireComponent(typeof(Sender)), ExecuteAlways]
|
[RequireComponent(typeof(Sender)), ExecuteAlways]
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
|
@ -23,7 +20,7 @@ public class SendChildrenToSpeckle : MonoBehaviour
|
||||||
{
|
{
|
||||||
sender = GetComponent<Sender>();
|
sender = GetComponent<Sender>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[ContextMenu(nameof(Send))]
|
[ContextMenu(nameof(Send))]
|
||||||
public void Send()
|
public void Send()
|
||||||
{
|
{
|
||||||
|
@ -31,30 +28,32 @@ public class SendChildrenToSpeckle : MonoBehaviour
|
||||||
.Where(t => t != this.transform)
|
.Where(t => t != this.transform)
|
||||||
.Select(o => o.gameObject)
|
.Select(o => o.gameObject)
|
||||||
.ToImmutableHashSet();
|
.ToImmutableHashSet();
|
||||||
|
|
||||||
Debug.Log("starting send...");
|
Debug.Log("starting send...");
|
||||||
sender.Send(streamId, selected, null, branchName, createCommit,
|
sender.Send(
|
||||||
|
streamId,
|
||||||
|
selected,
|
||||||
|
null,
|
||||||
|
branchName,
|
||||||
|
createCommit,
|
||||||
onErrorAction: OnError,
|
onErrorAction: OnError,
|
||||||
onProgressAction: OnProgress,
|
onProgressAction: OnProgress,
|
||||||
onDataSentAction: OnSent);
|
onDataSentAction: OnSent
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSent(string objectId)
|
private void OnSent(string objectId)
|
||||||
{
|
{
|
||||||
Debug.Log($"Data sent {objectId}", this);
|
Debug.Log($"Data sent {objectId}", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnError(string message, Exception e)
|
private void OnError(string message, Exception e)
|
||||||
{
|
{
|
||||||
Debug.LogError($"Error while sending {message} \n {e}", this);
|
Debug.LogError($"Error while sending {message} \n {e}", this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnProgress(ConcurrentDictionary<string, int> dict)
|
private void OnProgress(ConcurrentDictionary<string, int> dict)
|
||||||
{
|
{
|
||||||
Debug.Log($"progress was made", this);
|
Debug.Log($"progress was made", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,220 +1,244 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Speckle.Core.Api;
|
using Speckle.Core.Api;
|
||||||
using Speckle.Core.Logging;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using Text = UnityEngine.UI.Text;
|
using Text = UnityEngine.UI.Text;
|
||||||
|
|
||||||
namespace Speckle.ConnectorUnity
|
namespace Speckle.ConnectorUnity
|
||||||
{
|
{
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
public class InteractionLogic : MonoBehaviour
|
public class InteractionLogic : MonoBehaviour
|
||||||
{
|
|
||||||
private Receiver receiver;
|
|
||||||
|
|
||||||
public void InitReceiver(Stream stream, bool autoReceive)
|
|
||||||
{
|
{
|
||||||
gameObject.name = $"receiver-{stream.id}-{Guid.NewGuid().ToString()}";
|
private Receiver _receiver;
|
||||||
InitRemove();
|
|
||||||
|
|
||||||
receiver = gameObject.AddComponent<Receiver>();
|
public void InitReceiver(Stream stream, bool autoReceive)
|
||||||
receiver.Stream = stream;
|
|
||||||
|
|
||||||
var btn = gameObject.transform.Find("Btn").GetComponentInChildren<Button>();
|
|
||||||
var streamText = gameObject.transform.Find("StreamText").GetComponentInChildren<Text>();
|
|
||||||
var statusText = gameObject.transform.Find("StatusText").GetComponentInChildren<Text>();
|
|
||||||
var branchesDropdown = gameObject.transform.Find("Dropdown").GetComponentInChildren<Dropdown>();
|
|
||||||
var receiveProgress = btn.GetComponentInChildren<Slider>();
|
|
||||||
receiveProgress.gameObject.SetActive(false); //hide
|
|
||||||
|
|
||||||
//populate branches
|
|
||||||
branchesDropdown.options.Clear();
|
|
||||||
List<Branch> branches = receiver.Stream.branches.items;
|
|
||||||
branches.Reverse();
|
|
||||||
foreach (Branch branch in branches)
|
|
||||||
{
|
|
||||||
branchesDropdown.options.Add(new Dropdown.OptionData(branch.name.Replace(' ', '\u00A0')));
|
|
||||||
}
|
|
||||||
|
|
||||||
//trigger ui refresh, maybe there's a better method
|
|
||||||
branchesDropdown.value = -1;
|
|
||||||
branchesDropdown.value = 0;
|
|
||||||
branchesDropdown.onValueChanged.AddListener(index =>
|
|
||||||
{
|
|
||||||
if (index == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
receiver.BranchName = branches[index].name;
|
|
||||||
});
|
|
||||||
|
|
||||||
receiver.Init(stream.id, autoReceive, true,
|
|
||||||
onDataReceivedAction: (go) =>
|
|
||||||
{
|
{
|
||||||
statusText.text = $"Received {go.name}";
|
gameObject.name = $"receiver-{stream.id}-{Guid.NewGuid().ToString()}";
|
||||||
MakeButtonsInteractable(true);
|
InitRemove();
|
||||||
receiveProgress.value = 0;
|
|
||||||
receiveProgress.gameObject.SetActive(false);
|
|
||||||
|
|
||||||
AddComponents(go);
|
_receiver = gameObject.AddComponent<Receiver>();
|
||||||
},
|
_receiver.Stream = stream;
|
||||||
onTotalChildrenCountKnown: (count) => { receiver.TotalChildrenCount = count; },
|
|
||||||
onProgressAction: (dict) =>
|
|
||||||
{
|
|
||||||
//Run on a dispatcher as GOs can only be retrieved on the main thread
|
|
||||||
Dispatcher.Instance().Enqueue(() =>
|
|
||||||
{
|
|
||||||
var val = dict.Values.Average() / receiver.TotalChildrenCount;
|
|
||||||
receiveProgress.gameObject.SetActive(true);
|
|
||||||
receiveProgress.value = (float) val;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
var btn = gameObject.transform.Find("Btn").GetComponentInChildren<Button>();
|
||||||
|
var streamText = gameObject.transform.Find("StreamText").GetComponentInChildren<Text>();
|
||||||
|
var statusText = gameObject.transform.Find("StatusText").GetComponentInChildren<Text>();
|
||||||
|
var branchesDropdown = gameObject.transform
|
||||||
|
.Find("Dropdown")
|
||||||
|
.GetComponentInChildren<Dropdown>();
|
||||||
|
var receiveProgress = btn.GetComponentInChildren<Slider>();
|
||||||
|
receiveProgress.gameObject.SetActive(false); //hide
|
||||||
|
|
||||||
streamText.text = $"Stream: {stream.name}\nId: {stream.id} - Auto: {autoReceive}";
|
//populate branches
|
||||||
btn.onClick.AddListener(() =>
|
branchesDropdown.options.Clear();
|
||||||
{
|
List<Branch> branches = _receiver.Stream.branches.items;
|
||||||
statusText.text = "Receiving...";
|
branches.Reverse();
|
||||||
MakeButtonsInteractable(false);
|
foreach (Branch branch in branches)
|
||||||
receiver.Receive();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Recursively adds custom components to all children of a GameObject
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="go"></param>
|
|
||||||
private void AddComponents(GameObject go)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < go.transform.childCount; i++)
|
|
||||||
{
|
|
||||||
var child = go.transform.GetChild(i);
|
|
||||||
|
|
||||||
if (child.childCount > 0)
|
|
||||||
{
|
|
||||||
AddComponents(child.gameObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
child.gameObject.AddComponent<Selectable>();
|
|
||||||
|
|
||||||
//Add extra Components
|
|
||||||
//var rigidbody = child.gameObject.AddComponent<Rigidbody>();
|
|
||||||
//rigidbody.mass = 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void InitSender(Stream stream)
|
|
||||||
{
|
|
||||||
gameObject.name = $"sender-{stream.id}-{Guid.NewGuid().ToString()}";
|
|
||||||
InitRemove();
|
|
||||||
|
|
||||||
var sender = gameObject.AddComponent<Sender>();
|
|
||||||
var btn = gameObject.transform.Find("Btn").GetComponentInChildren<Button>();
|
|
||||||
|
|
||||||
var streamText = gameObject.transform.Find("StreamText").GetComponentInChildren<Text>();
|
|
||||||
var statusText = gameObject.transform.Find("StatusText").GetComponentInChildren<Text>();
|
|
||||||
|
|
||||||
btn.GetComponentInChildren<Text>().text = "Send";
|
|
||||||
statusText.text = "Ready to send";
|
|
||||||
|
|
||||||
var sendProgress = btn.GetComponentInChildren<Slider>();
|
|
||||||
sendProgress.gameObject.SetActive(false); //hide
|
|
||||||
|
|
||||||
streamText.text = $"Stream: {stream.name}\nId: {stream.id}";
|
|
||||||
|
|
||||||
|
|
||||||
btn.onClick.AddListener(() =>
|
|
||||||
{
|
|
||||||
var objs = SelectionManager.selectedObjects.Select(s => s.gameObject).ToImmutableHashSet();
|
|
||||||
|
|
||||||
if (!objs.Any())
|
|
||||||
{
|
|
||||||
statusText.text = $"No objects selected";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MakeButtonsInteractable(false);
|
|
||||||
|
|
||||||
statusText.text = "Sending...";
|
|
||||||
try
|
|
||||||
{
|
|
||||||
sender.Send(stream.id, objs,
|
|
||||||
onProgressAction: (dict) =>
|
|
||||||
{
|
|
||||||
//Run on a dispatcher as GOs can only be retrieved on the main thread
|
|
||||||
Dispatcher.Instance().Enqueue(() =>
|
|
||||||
{
|
|
||||||
var val = dict.Values.Average() / objs.Count;
|
|
||||||
sendProgress.gameObject.SetActive(true);
|
|
||||||
sendProgress.value = (float) val;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onDataSentAction: (objectId) =>
|
|
||||||
{
|
|
||||||
Debug.Log($"Send operation completed, object id: {objectId}", this);
|
|
||||||
Dispatcher.Instance().Enqueue(() =>
|
|
||||||
{
|
|
||||||
MakeButtonsInteractable(true);
|
|
||||||
statusText.text = $"Sent {objectId}";
|
|
||||||
sendProgress.gameObject.SetActive(false); //hide
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onErrorAction: (message, e) =>
|
|
||||||
{
|
|
||||||
Debug.LogError("Send operation Failed!", this);
|
|
||||||
Dispatcher.Instance().Enqueue(() =>
|
|
||||||
{
|
|
||||||
MakeButtonsInteractable(true);
|
|
||||||
statusText.text = $"Error {message}";
|
|
||||||
sendProgress.gameObject.SetActive(false); //hide
|
|
||||||
Debug.LogError(e, this);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
Dispatcher.Instance().Enqueue(() =>
|
|
||||||
{
|
{
|
||||||
MakeButtonsInteractable(true);
|
branchesDropdown.options.Add(
|
||||||
statusText.text = $"Error {e.Message}";
|
new Dropdown.OptionData(branch.name.Replace(' ', '\u00A0'))
|
||||||
sendProgress.gameObject.SetActive(false); //hide
|
);
|
||||||
Debug.LogError(e, this);
|
}
|
||||||
|
|
||||||
|
//trigger ui refresh, maybe there's a better method
|
||||||
|
branchesDropdown.value = -1;
|
||||||
|
branchesDropdown.value = 0;
|
||||||
|
branchesDropdown.onValueChanged.AddListener(index =>
|
||||||
|
{
|
||||||
|
if (index == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_receiver.BranchName = branches[index].name;
|
||||||
|
});
|
||||||
|
|
||||||
|
_receiver.Init(
|
||||||
|
stream.id,
|
||||||
|
autoReceive,
|
||||||
|
onDataReceivedAction: (go) =>
|
||||||
|
{
|
||||||
|
statusText.text = $"Received {go.name}";
|
||||||
|
MakeButtonsInteractable(true);
|
||||||
|
receiveProgress.value = 0;
|
||||||
|
receiveProgress.gameObject.SetActive(false);
|
||||||
|
|
||||||
|
AddComponents(go);
|
||||||
|
},
|
||||||
|
onTotalChildrenCountKnown: (count) =>
|
||||||
|
{
|
||||||
|
_receiver.TotalChildrenCount = count;
|
||||||
|
},
|
||||||
|
onProgressAction: (dict) =>
|
||||||
|
{
|
||||||
|
//Run on a dispatcher as GOs can only be retrieved on the main thread
|
||||||
|
Dispatcher
|
||||||
|
.Instance()
|
||||||
|
.Enqueue(() =>
|
||||||
|
{
|
||||||
|
var val = dict.Values.Average() / _receiver.TotalChildrenCount;
|
||||||
|
receiveProgress.gameObject.SetActive(true);
|
||||||
|
receiveProgress.value = (float)val;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
streamText.text = $"Stream: {stream.name}\nId: {stream.id} - Auto: {autoReceive}";
|
||||||
|
btn.onClick.AddListener(() =>
|
||||||
|
{
|
||||||
|
statusText.text = "Receiving...";
|
||||||
|
MakeButtonsInteractable(false);
|
||||||
|
_receiver.Receive();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MakeButtonsInteractable(bool interactable)
|
/// <summary>
|
||||||
{
|
/// Recursively adds custom components to all children of a GameObject
|
||||||
var selectables = gameObject.transform.GetComponentsInChildren<UnityEngine.UI.Selectable>();
|
/// </summary>
|
||||||
foreach (var selectable in selectables)
|
/// <param name="go"></param>
|
||||||
{
|
private void AddComponents(GameObject go)
|
||||||
selectable.interactable = interactable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitRemove()
|
|
||||||
{
|
|
||||||
var close = gameObject.transform.Find("Close").GetComponentInChildren<Button>();
|
|
||||||
|
|
||||||
close.onClick.AddListener(() =>
|
|
||||||
{
|
|
||||||
//remove received geometry
|
|
||||||
if (receiver != null)
|
|
||||||
{
|
{
|
||||||
Destroy(receiver.ReceivedData);
|
for (var i = 0; i < go.transform.childCount; i++)
|
||||||
|
{
|
||||||
|
var child = go.transform.GetChild(i);
|
||||||
|
|
||||||
|
if (child.childCount > 0)
|
||||||
|
{
|
||||||
|
AddComponents(child.gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
child.gameObject.AddComponent<Selectable>();
|
||||||
|
|
||||||
|
//Add extra Components
|
||||||
|
//var rigidbody = child.gameObject.AddComponent<Rigidbody>();
|
||||||
|
//rigidbody.mass = 10;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//update ui
|
public void InitSender(Stream stream)
|
||||||
GameObject.Find("_SpeckleExamples").GetComponent<SpeckleExamples>().RemoveStreamPrefab(gameObject);
|
{
|
||||||
|
gameObject.name = $"sender-{stream.id}-{Guid.NewGuid().ToString()}";
|
||||||
|
InitRemove();
|
||||||
|
|
||||||
//kill it
|
var sender = gameObject.AddComponent<Sender>();
|
||||||
Destroy(gameObject);
|
var btn = gameObject.transform.Find("Btn").GetComponentInChildren<Button>();
|
||||||
});
|
|
||||||
|
var streamText = gameObject.transform.Find("StreamText").GetComponentInChildren<Text>();
|
||||||
|
var statusText = gameObject.transform.Find("StatusText").GetComponentInChildren<Text>();
|
||||||
|
|
||||||
|
btn.GetComponentInChildren<Text>().text = "Send";
|
||||||
|
statusText.text = "Ready to send";
|
||||||
|
|
||||||
|
var sendProgress = btn.GetComponentInChildren<Slider>();
|
||||||
|
sendProgress.gameObject.SetActive(false); //hide
|
||||||
|
|
||||||
|
streamText.text = $"Stream: {stream.name}\nId: {stream.id}";
|
||||||
|
|
||||||
|
btn.onClick.AddListener(() =>
|
||||||
|
{
|
||||||
|
var objs = SelectionManager.selectedObjects
|
||||||
|
.Select(s => s.gameObject)
|
||||||
|
.ToImmutableHashSet();
|
||||||
|
|
||||||
|
if (!objs.Any())
|
||||||
|
{
|
||||||
|
statusText.text = $"No objects selected";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MakeButtonsInteractable(false);
|
||||||
|
|
||||||
|
statusText.text = "Sending...";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sender.Send(
|
||||||
|
stream.id,
|
||||||
|
objs,
|
||||||
|
onProgressAction: (dict) =>
|
||||||
|
{
|
||||||
|
//Run on a dispatcher as GOs can only be retrieved on the main thread
|
||||||
|
Dispatcher
|
||||||
|
.Instance()
|
||||||
|
.Enqueue(() =>
|
||||||
|
{
|
||||||
|
var val = dict.Values.Average() / objs.Count;
|
||||||
|
sendProgress.gameObject.SetActive(true);
|
||||||
|
sendProgress.value = (float)val;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onDataSentAction: (objectId) =>
|
||||||
|
{
|
||||||
|
Debug.Log($"Send operation completed, object id: {objectId}", this);
|
||||||
|
Dispatcher
|
||||||
|
.Instance()
|
||||||
|
.Enqueue(() =>
|
||||||
|
{
|
||||||
|
MakeButtonsInteractable(true);
|
||||||
|
statusText.text = $"Sent {objectId}";
|
||||||
|
sendProgress.gameObject.SetActive(false); //hide
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onErrorAction: (message, e) =>
|
||||||
|
{
|
||||||
|
Debug.LogError("Send operation Failed!", this);
|
||||||
|
Dispatcher
|
||||||
|
.Instance()
|
||||||
|
.Enqueue(() =>
|
||||||
|
{
|
||||||
|
MakeButtonsInteractable(true);
|
||||||
|
statusText.text = $"Error {message}";
|
||||||
|
sendProgress.gameObject.SetActive(false); //hide
|
||||||
|
Debug.LogError(e, this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Dispatcher
|
||||||
|
.Instance()
|
||||||
|
.Enqueue(() =>
|
||||||
|
{
|
||||||
|
MakeButtonsInteractable(true);
|
||||||
|
statusText.text = $"Error {e.Message}";
|
||||||
|
sendProgress.gameObject.SetActive(false); //hide
|
||||||
|
Debug.LogError(e, this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MakeButtonsInteractable(bool interactable)
|
||||||
|
{
|
||||||
|
var selectables =
|
||||||
|
gameObject.transform.GetComponentsInChildren<UnityEngine.UI.Selectable>();
|
||||||
|
foreach (var selectable in selectables)
|
||||||
|
{
|
||||||
|
selectable.interactable = interactable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitRemove()
|
||||||
|
{
|
||||||
|
var close = gameObject.transform.Find("Close").GetComponentInChildren<Button>();
|
||||||
|
|
||||||
|
close.onClick.AddListener(() =>
|
||||||
|
{
|
||||||
|
//remove received geometry
|
||||||
|
if (_receiver != null)
|
||||||
|
{
|
||||||
|
Destroy(_receiver.ReceivedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
//update ui
|
||||||
|
GameObject
|
||||||
|
.Find("_SpeckleExamples")
|
||||||
|
.GetComponent<SpeckleExamples>()
|
||||||
|
.RemoveStreamPrefab(gameObject);
|
||||||
|
|
||||||
|
//kill it
|
||||||
|
Destroy(gameObject);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,125 +10,123 @@ using Stream = Speckle.Core.Api.Stream;
|
||||||
namespace Speckle.ConnectorUnity
|
namespace Speckle.ConnectorUnity
|
||||||
{
|
{
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
public class SpeckleExamples : MonoBehaviour
|
public class SpeckleExamples : MonoBehaviour
|
||||||
{
|
|
||||||
public Text SelectStreamText;
|
|
||||||
public Text DetailsStreamText;
|
|
||||||
public Dropdown StreamSelectionDropdown;
|
|
||||||
public Button AddReceiverBtn;
|
|
||||||
public Toggle AutoReceiveToggle;
|
|
||||||
public Button AddSenderBtn;
|
|
||||||
public GameObject StreamPanel;
|
|
||||||
public Canvas StreamsCanvas;
|
|
||||||
|
|
||||||
private List<Stream> StreamList = null;
|
|
||||||
private Stream SelectedStream = null;
|
|
||||||
private List<GameObject> StreamPanels = new List<GameObject>();
|
|
||||||
|
|
||||||
|
|
||||||
async void Start()
|
|
||||||
{
|
{
|
||||||
if (SelectStreamText == null || StreamSelectionDropdown == null)
|
public Text SelectStreamText;
|
||||||
{
|
public Text DetailsStreamText;
|
||||||
Debug.Log("Please set all input fields on _SpeckleExamples");
|
public Dropdown StreamSelectionDropdown;
|
||||||
return;
|
public Button AddReceiverBtn;
|
||||||
}
|
public Toggle AutoReceiveToggle;
|
||||||
|
public Button AddSenderBtn;
|
||||||
|
public GameObject StreamPanel;
|
||||||
|
public Canvas StreamsCanvas;
|
||||||
|
|
||||||
var defaultAccount = AccountManager.GetDefaultAccount();
|
private List<Stream> StreamList = null;
|
||||||
if (defaultAccount == null)
|
private Stream SelectedStream = null;
|
||||||
{
|
private List<GameObject> StreamPanels = new List<GameObject>();
|
||||||
Debug.Log("Please set a default account in SpeckleManager");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectStreamText.text = $"Select a stream on {defaultAccount.serverInfo.name}:";
|
async void Start()
|
||||||
|
{
|
||||||
|
if (SelectStreamText == null || StreamSelectionDropdown == null)
|
||||||
|
{
|
||||||
|
Debug.Log("Please set all input fields on _SpeckleExamples");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
StreamList = await Streams.List(30);
|
var defaultAccount = AccountManager.GetDefaultAccount();
|
||||||
if (!StreamList.Any())
|
if (defaultAccount == null)
|
||||||
{
|
{
|
||||||
Debug.Log("There are no streams in your account, please create one online.");
|
Debug.Log("Please set a default account in SpeckleManager");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamSelectionDropdown.options.Clear();
|
SelectStreamText.text = $"Select a stream on {defaultAccount.serverInfo.name}:";
|
||||||
foreach (var stream in StreamList)
|
|
||||||
{
|
|
||||||
StreamSelectionDropdown.options.Add(new Dropdown.OptionData(stream.name + " - " + stream.id));
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamSelectionDropdown.onValueChanged.AddListener(StreamSelectionChanged);
|
StreamList = await Streams.List(30);
|
||||||
//trigger ui refresh, maybe there's a better method
|
if (!StreamList.Any())
|
||||||
StreamSelectionDropdown.value = -1;
|
{
|
||||||
StreamSelectionDropdown.value = 0;
|
Debug.Log("There are no streams in your account, please create one online.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamSelectionDropdown.options.Clear();
|
||||||
|
foreach (var stream in StreamList)
|
||||||
|
{
|
||||||
|
StreamSelectionDropdown.options.Add(
|
||||||
|
new Dropdown.OptionData(stream.name + " - " + stream.id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
AddReceiverBtn.onClick.AddListener(AddReceiver);
|
StreamSelectionDropdown.onValueChanged.AddListener(StreamSelectionChanged);
|
||||||
AddSenderBtn.onClick.AddListener(AddSender);
|
//trigger ui refresh, maybe there's a better method
|
||||||
|
StreamSelectionDropdown.value = -1;
|
||||||
|
StreamSelectionDropdown.value = 0;
|
||||||
|
|
||||||
|
AddReceiverBtn.onClick.AddListener(AddReceiver);
|
||||||
|
AddSenderBtn.onClick.AddListener(AddSender);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StreamSelectionChanged(int index)
|
||||||
|
{
|
||||||
|
if (index == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SelectedStream = StreamList[index];
|
||||||
|
DetailsStreamText.text =
|
||||||
|
$"Description: {SelectedStream.description}\n"
|
||||||
|
+ $"Link sharing on: {SelectedStream.isPublic}\n"
|
||||||
|
+ $"Role: {SelectedStream.role}\n"
|
||||||
|
+ $"Collaborators: {SelectedStream.collaborators.Count}\n"
|
||||||
|
+ $"Id: {SelectedStream.id}";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shows how to create a new Receiver from code and then pull data manually
|
||||||
|
// Created receivers are added to a List of Receivers for future use
|
||||||
|
private async void AddReceiver()
|
||||||
|
{
|
||||||
|
var autoReceive = AutoReceiveToggle.isOn;
|
||||||
|
var stream = await Streams.Get(SelectedStream.id, 30);
|
||||||
|
|
||||||
|
var streamPrefab = Instantiate(StreamPanel, new Vector3(0, 0, 0), Quaternion.identity);
|
||||||
|
|
||||||
|
//set position
|
||||||
|
streamPrefab.transform.SetParent(StreamsCanvas.transform);
|
||||||
|
var rt = streamPrefab.GetComponent<RectTransform>();
|
||||||
|
rt.anchoredPosition = new Vector3(-10, -110 - StreamPanels.Count * 110, 0);
|
||||||
|
|
||||||
|
streamPrefab.AddComponent<InteractionLogic>().InitReceiver(stream, autoReceive);
|
||||||
|
|
||||||
|
StreamPanels.Add(streamPrefab);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void AddSender()
|
||||||
|
{
|
||||||
|
var stream = await Streams.Get(SelectedStream.id, 10);
|
||||||
|
|
||||||
|
var streamPrefab = Instantiate(StreamPanel, new Vector3(0, 0, 0), Quaternion.identity);
|
||||||
|
|
||||||
|
streamPrefab.transform.SetParent(StreamsCanvas.transform);
|
||||||
|
var rt = streamPrefab.GetComponent<RectTransform>();
|
||||||
|
rt.anchoredPosition = new Vector3(-10, -110 - StreamPanels.Count * 110, 0);
|
||||||
|
|
||||||
|
streamPrefab.AddComponent<InteractionLogic>().InitSender(stream);
|
||||||
|
|
||||||
|
StreamPanels.Add(streamPrefab);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveStreamPrefab(GameObject streamPrefab)
|
||||||
|
{
|
||||||
|
StreamPanels.RemoveAt(StreamPanels.FindIndex(x => x.name == streamPrefab.name));
|
||||||
|
ReorderStreamPrefabs();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReorderStreamPrefabs()
|
||||||
|
{
|
||||||
|
for (var i = 0; i < StreamPanels.Count; i++)
|
||||||
|
{
|
||||||
|
var rt = StreamPanels[i].GetComponent<RectTransform>();
|
||||||
|
rt.anchoredPosition = new Vector3(-10, -110 - i * 110, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StreamSelectionChanged(int index)
|
|
||||||
{
|
|
||||||
if (index == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
SelectedStream = StreamList[index];
|
|
||||||
DetailsStreamText.text =
|
|
||||||
$"Description: {SelectedStream.description}\n" +
|
|
||||||
$"Link sharing on: {SelectedStream.isPublic}\n" +
|
|
||||||
$"Role: {SelectedStream.role}\n" +
|
|
||||||
$"Collaborators: {SelectedStream.collaborators.Count}\n" +
|
|
||||||
$"Id: {SelectedStream.id}";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shows how to create a new Receiver from code and then pull data manually
|
|
||||||
// Created receivers are added to a List of Receivers for future use
|
|
||||||
private async void AddReceiver()
|
|
||||||
{
|
|
||||||
var autoReceive = AutoReceiveToggle.isOn;
|
|
||||||
var stream = await Streams.Get(SelectedStream.id, 30);
|
|
||||||
|
|
||||||
var streamPrefab = Instantiate(StreamPanel, new Vector3(0, 0, 0),
|
|
||||||
Quaternion.identity);
|
|
||||||
|
|
||||||
//set position
|
|
||||||
streamPrefab.transform.SetParent(StreamsCanvas.transform);
|
|
||||||
var rt = streamPrefab.GetComponent<RectTransform>();
|
|
||||||
rt.anchoredPosition = new Vector3(-10, -110 - StreamPanels.Count * 110, 0);
|
|
||||||
|
|
||||||
streamPrefab.AddComponent<InteractionLogic>().InitReceiver(stream, autoReceive);
|
|
||||||
|
|
||||||
StreamPanels.Add(streamPrefab);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void AddSender()
|
|
||||||
{
|
|
||||||
var stream = await Streams.Get(SelectedStream.id, 10);
|
|
||||||
|
|
||||||
var streamPrefab = Instantiate(StreamPanel, new Vector3(0, 0, 0),
|
|
||||||
Quaternion.identity);
|
|
||||||
|
|
||||||
streamPrefab.transform.SetParent(StreamsCanvas.transform);
|
|
||||||
var rt = streamPrefab.GetComponent<RectTransform>();
|
|
||||||
rt.anchoredPosition = new Vector3(-10, -110 - StreamPanels.Count * 110, 0);
|
|
||||||
|
|
||||||
streamPrefab.AddComponent<InteractionLogic>().InitSender(stream);
|
|
||||||
|
|
||||||
StreamPanels.Add(streamPrefab);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveStreamPrefab(GameObject streamPrefab)
|
|
||||||
{
|
|
||||||
StreamPanels.RemoveAt(StreamPanels.FindIndex(x => x.name == streamPrefab.name));
|
|
||||||
ReorderStreamPrefabs();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ReorderStreamPrefabs()
|
|
||||||
{
|
|
||||||
for (var i = 0; i < StreamPanels.Count; i++)
|
|
||||||
{
|
|
||||||
var rt = StreamPanels[i].GetComponent<RectTransform>();
|
|
||||||
rt.anchoredPosition = new Vector3(-10, -110 - i * 110, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,28 +13,29 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
[CustomEditor(typeof(SpeckleReceiver))]
|
[CustomEditor(typeof(SpeckleReceiver))]
|
||||||
public class SpeckleReceiverEditor : UnityEditor.Editor
|
public class SpeckleReceiverEditor : UnityEditor.Editor
|
||||||
{
|
{
|
||||||
private static bool generateAssets = false;
|
private static bool _generateAssets = false;
|
||||||
private bool foldOutStatus = true;
|
private bool _foldOutStatus = true;
|
||||||
private Texture2D? previewImage;
|
private Texture2D? _previewImage;
|
||||||
|
|
||||||
public override async void OnInspectorGUI()
|
public override async void OnInspectorGUI()
|
||||||
{
|
{
|
||||||
var speckleReceiver = (SpeckleReceiver)target;
|
var speckleReceiver = (SpeckleReceiver)target;
|
||||||
|
|
||||||
DrawDefaultInspector();
|
DrawDefaultInspector();
|
||||||
|
|
||||||
//Preview image
|
//Preview image
|
||||||
{
|
{
|
||||||
foldOutStatus = EditorGUILayout.Foldout(foldOutStatus, "Preview Image");
|
_foldOutStatus = EditorGUILayout.Foldout(_foldOutStatus, "Preview Image");
|
||||||
if (foldOutStatus)
|
if (_foldOutStatus)
|
||||||
{
|
{
|
||||||
Rect rect = GUILayoutUtility.GetAspectRect(7f / 4f);
|
Rect rect = GUILayoutUtility.GetAspectRect(7f / 4f);
|
||||||
if (previewImage != null) GUI.DrawTexture(rect, previewImage);
|
if (_previewImage != null)
|
||||||
|
GUI.DrawTexture(rect, _previewImage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Draw events in a collapsed region
|
//TODO: Draw events in a collapsed region
|
||||||
|
|
||||||
//Receive settings
|
//Receive settings
|
||||||
{
|
{
|
||||||
bool prev = GUI.enabled;
|
bool prev = GUI.enabled;
|
||||||
|
@ -42,10 +43,10 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
//Receive button
|
//Receive button
|
||||||
bool userRequestedReceive = GUILayout.Button("Receive!");
|
bool userRequestedReceive = GUILayout.Button("Receive!");
|
||||||
|
|
||||||
bool selection = EditorGUILayout.ToggleLeft("Generate Assets", generateAssets);
|
bool selection = EditorGUILayout.ToggleLeft("Generate Assets", _generateAssets);
|
||||||
if (generateAssets != selection)
|
if (_generateAssets != selection)
|
||||||
{
|
{
|
||||||
generateAssets = selection;
|
_generateAssets = selection;
|
||||||
UpdateGenerateAssets();
|
UpdateGenerateAssets();
|
||||||
}
|
}
|
||||||
GUI.enabled = prev;
|
GUI.enabled = prev;
|
||||||
|
@ -54,14 +55,19 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
{
|
{
|
||||||
var value = Progress.globalProgress; //NOTE: this may include non-speckle items...
|
var value = Progress.globalProgress; //NOTE: this may include non-speckle items...
|
||||||
var percent = Math.Max(0, Mathf.Ceil(value * 100));
|
var percent = Math.Max(0, Mathf.Ceil(value * 100));
|
||||||
var rect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight);
|
var rect = EditorGUILayout.GetControlRect(
|
||||||
|
false,
|
||||||
|
EditorGUIUtility.singleLineHeight
|
||||||
|
);
|
||||||
EditorGUI.ProgressBar(rect, value, $"{percent}%");
|
EditorGUI.ProgressBar(rect, value, $"{percent}%");
|
||||||
}
|
}
|
||||||
else if (userRequestedReceive)
|
else if (userRequestedReceive)
|
||||||
{
|
{
|
||||||
var id = Progress.Start(
|
var id = Progress.Start(
|
||||||
"Receiving Speckle data",
|
"Receiving Speckle data",
|
||||||
"Fetching commit data", Progress.Options.Sticky);
|
"Fetching commit data",
|
||||||
|
Progress.Options.Sticky
|
||||||
|
);
|
||||||
Progress.ShowDetails();
|
Progress.ShowDetails();
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -86,21 +92,20 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnEnable()
|
public void OnEnable()
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void Init()
|
private void Init()
|
||||||
{
|
{
|
||||||
var speckleReceiver = (SpeckleReceiver) target;
|
var speckleReceiver = (SpeckleReceiver)target;
|
||||||
UpdatePreviewImage();
|
UpdatePreviewImage();
|
||||||
speckleReceiver.OnCommitSelectionChange.AddListener(_ => UpdatePreviewImage());
|
speckleReceiver.OnCommitSelectionChange.AddListener(_ => UpdatePreviewImage());
|
||||||
UpdateGenerateAssets();
|
UpdateGenerateAssets();
|
||||||
|
@ -108,31 +113,35 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
|
|
||||||
private void UpdatePreviewImage()
|
private void UpdatePreviewImage()
|
||||||
{
|
{
|
||||||
previewImage = null;
|
_previewImage = null;
|
||||||
((SpeckleReceiver)target).GetPreviewImage(t => previewImage = t);
|
((SpeckleReceiver)target).GetPreviewImage(t => _previewImage = t);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ReceiveSelection(int progressId)
|
private async Task ReceiveSelection(int progressId)
|
||||||
{
|
{
|
||||||
var speckleReceiver = (SpeckleReceiver)target;
|
var speckleReceiver = (SpeckleReceiver)target;
|
||||||
|
|
||||||
bool shouldCancel = false;
|
bool shouldCancel = false;
|
||||||
|
|
||||||
Progress.RegisterCancelCallback(progressId, () =>
|
Progress.RegisterCancelCallback(
|
||||||
{
|
progressId,
|
||||||
speckleReceiver.Cancel();
|
() =>
|
||||||
shouldCancel = true;
|
{
|
||||||
return true;
|
speckleReceiver.Cancel();
|
||||||
});
|
shouldCancel = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
Base commitObject;
|
Base commitObject;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var token = speckleReceiver.BeginOperation();
|
var token = speckleReceiver.BeginOperation();
|
||||||
commitObject = await Task.Run(async () => await ReceiveCommit(progressId).ConfigureAwait(false),
|
commitObject = await Task.Run(
|
||||||
token
|
async () => await ReceiveCommit(progressId).ConfigureAwait(false),
|
||||||
)
|
token
|
||||||
.ConfigureAwait(true);
|
)
|
||||||
|
.ConfigureAwait(true);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -142,32 +151,42 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
int childrenConverted = 0;
|
int childrenConverted = 0;
|
||||||
int childrenFailed = 0;
|
int childrenFailed = 0;
|
||||||
|
|
||||||
int totalChildren = (int) Math.Min(commitObject.totalChildrenCount, int.MaxValue);
|
int totalChildren = (int)Math.Min(commitObject.totalChildrenCount, int.MaxValue);
|
||||||
float totalChildrenFloat = commitObject.totalChildrenCount;
|
float totalChildrenFloat = commitObject.totalChildrenCount;
|
||||||
|
|
||||||
var convertProgress = Progress.Start("Converting To Native", "Preparing...", Progress.Options.Indefinite | Progress.Options.Sticky, progressId);
|
var convertProgress = Progress.Start(
|
||||||
|
"Converting To Native",
|
||||||
|
"Preparing...",
|
||||||
|
Progress.Options.Indefinite | Progress.Options.Sticky,
|
||||||
|
progressId
|
||||||
|
);
|
||||||
|
|
||||||
bool BeforeConvert(TraversalContext context)
|
bool BeforeConvert(TraversalContext context)
|
||||||
{
|
{
|
||||||
Base b = context.current;
|
Base b = context.current;
|
||||||
|
|
||||||
//NOTE: progress wont reach 100% because not all objects are convertable
|
//NOTE: progress wont reach 100% because not all objects are convertable
|
||||||
float progress = (childrenConverted + childrenFailed) / totalChildrenFloat;
|
float progress = (childrenConverted + childrenFailed) / totalChildrenFloat;
|
||||||
|
|
||||||
if (shouldCancel) return false;
|
if (shouldCancel)
|
||||||
|
return false;
|
||||||
|
|
||||||
shouldCancel = EditorUtility.DisplayCancelableProgressBar(
|
shouldCancel = EditorUtility.DisplayCancelableProgressBar(
|
||||||
"Converting To Native...",
|
"Converting To Native...",
|
||||||
$"{b.speckle_type} - {b.id}",
|
$"{b.speckle_type} - {b.id}",
|
||||||
progress);
|
progress
|
||||||
|
);
|
||||||
|
|
||||||
return !shouldCancel;
|
return !shouldCancel;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var conversionResult in speckleReceiver.Converter.RecursivelyConvertToNative_Enumerable(
|
foreach (
|
||||||
commitObject,
|
var conversionResult in speckleReceiver.Converter.RecursivelyConvertToNative_Enumerable(
|
||||||
speckleReceiver.transform,
|
commitObject,
|
||||||
BeforeConvert))
|
speckleReceiver.transform,
|
||||||
|
BeforeConvert
|
||||||
|
)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Base speckleObject = conversionResult.SpeckleObject;
|
Base speckleObject = conversionResult.SpeckleObject;
|
||||||
if (conversionResult.WasSuccessful(out _, out var ex))
|
if (conversionResult.WasSuccessful(out _, out var ex))
|
||||||
|
@ -179,31 +198,45 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
childrenFailed++;
|
childrenFailed++;
|
||||||
Debug.LogWarning(
|
Debug.LogWarning(
|
||||||
$"Failed to convert Speckle object of type {speckleObject.speckle_type}\n{ex}",
|
$"Failed to convert Speckle object of type {speckleObject.speckle_type}\n{ex}",
|
||||||
this);
|
this
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Progress.Report(progressId, childrenConverted + childrenFailed, totalChildren, "Receiving objects");
|
Progress.Report(
|
||||||
|
progressId,
|
||||||
|
childrenConverted + childrenFailed,
|
||||||
|
totalChildren,
|
||||||
|
"Receiving objects"
|
||||||
|
);
|
||||||
|
|
||||||
if (shouldCancel) break;
|
if (shouldCancel)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var resultString = $"{childrenConverted} {nameof(GameObject)}s created";
|
var resultString = $"{childrenConverted} {nameof(GameObject)}s created";
|
||||||
if (childrenFailed != 0) resultString += $", {childrenFailed} objects failed to convert!";
|
if (childrenFailed != 0)
|
||||||
|
resultString += $", {childrenFailed} objects failed to convert!";
|
||||||
Debug.Log(shouldCancel
|
|
||||||
|
Debug.Log(
|
||||||
|
shouldCancel
|
||||||
? $"Stopped converting to native: The operation has been cancelled - {resultString}\n "
|
? $"Stopped converting to native: The operation has been cancelled - {resultString}\n "
|
||||||
: $"Finished converting to native.\n{resultString}",
|
: $"Finished converting to native.\n{resultString}",
|
||||||
speckleReceiver);
|
speckleReceiver
|
||||||
|
);
|
||||||
|
|
||||||
Progress.Finish(convertProgress);
|
Progress.Finish(convertProgress);
|
||||||
|
|
||||||
if (shouldCancel) throw new OperationCanceledException("Conversion operation canceled through editor dialogue");
|
if (shouldCancel)
|
||||||
|
throw new OperationCanceledException(
|
||||||
|
"Conversion operation canceled through editor dialogue"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateGenerateAssets()
|
private void UpdateGenerateAssets()
|
||||||
{
|
{
|
||||||
var speckleReceiver = (SpeckleReceiver) target;
|
var speckleReceiver = (SpeckleReceiver)target;
|
||||||
speckleReceiver.Converter.AssetCache.nativeCaches = NativeCacheFactory.GetDefaultNativeCacheSetup(generateAssets);
|
speckleReceiver.Converter.AssetCache.nativeCaches =
|
||||||
|
NativeCacheFactory.GetDefaultNativeCacheSetup(_generateAssets);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Base> ReceiveCommit(int progressId)
|
private async Task<Base> ReceiveCommit(int progressId)
|
||||||
|
@ -211,9 +244,19 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
var speckleReceiver = (SpeckleReceiver)target;
|
var speckleReceiver = (SpeckleReceiver)target;
|
||||||
|
|
||||||
string serverLogName = speckleReceiver.Account.Client?.ServerUrl ?? "Speckle";
|
string serverLogName = speckleReceiver.Account.Client?.ServerUrl ?? "Speckle";
|
||||||
|
|
||||||
int transport = Progress.Start($"Downloading data from {serverLogName}", "Waiting...", Progress.Options.Sticky, progressId);
|
int transport = Progress.Start(
|
||||||
int deserialize = Progress.Start("Deserializing data", "Waiting...", Progress.Options.Sticky, progressId);
|
$"Downloading data from {serverLogName}",
|
||||||
|
"Waiting...",
|
||||||
|
Progress.Options.Sticky,
|
||||||
|
progressId
|
||||||
|
);
|
||||||
|
int deserialize = Progress.Start(
|
||||||
|
"Deserializing data",
|
||||||
|
"Waiting...",
|
||||||
|
Progress.Options.Sticky,
|
||||||
|
progressId
|
||||||
|
);
|
||||||
Progress.SetPriority(transport, Progress.Priority.High);
|
Progress.SetPriority(transport, Progress.Priority.High);
|
||||||
|
|
||||||
var totalObjectCount = 1;
|
var totalObjectCount = 1;
|
||||||
|
@ -222,7 +265,7 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
totalObjectCount = count;
|
totalObjectCount = count;
|
||||||
Progress.Report(progressId, 0, totalObjectCount, "Receiving objects");
|
Progress.Report(progressId, 0, totalObjectCount, "Receiving objects");
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnProgress(ConcurrentDictionary<string, int> dict)
|
void OnProgress(ConcurrentDictionary<string, int> dict)
|
||||||
{
|
{
|
||||||
bool r = dict.TryGetValue("RemoteTransport", out int rtProgress);
|
bool r = dict.TryGetValue("RemoteTransport", out int rtProgress);
|
||||||
|
@ -230,14 +273,24 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
if (r || l)
|
if (r || l)
|
||||||
{
|
{
|
||||||
var fetched = (rtProgress + ltProgress);
|
var fetched = (rtProgress + ltProgress);
|
||||||
Progress.Report(transport, fetched, totalObjectCount, $"{fetched}/{totalObjectCount}");
|
Progress.Report(
|
||||||
|
transport,
|
||||||
|
fetched,
|
||||||
|
totalObjectCount,
|
||||||
|
$"{fetched}/{totalObjectCount}"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dict.TryGetValue("DS", out int tsProgress))
|
if (dict.TryGetValue("DS", out int tsProgress))
|
||||||
{
|
{
|
||||||
tsProgress--; //The root object isn't included, so we add an extra 1
|
tsProgress--; //The root object isn't included, so we add an extra 1
|
||||||
Progress.Report(deserialize,tsProgress, totalObjectCount, $"{tsProgress}/{totalObjectCount}");
|
Progress.Report(
|
||||||
Progress.Report(progressId,tsProgress, totalObjectCount);
|
deserialize,
|
||||||
|
tsProgress,
|
||||||
|
totalObjectCount,
|
||||||
|
$"{tsProgress}/{totalObjectCount}"
|
||||||
|
);
|
||||||
|
Progress.Report(progressId, tsProgress, totalObjectCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,18 +299,19 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
{
|
{
|
||||||
speckleReceiver.OnTotalChildrenCountKnown.AddListener(OnTotalChildrenKnown);
|
speckleReceiver.OnTotalChildrenCountKnown.AddListener(OnTotalChildrenKnown);
|
||||||
speckleReceiver.OnReceiveProgressAction.AddListener(OnProgress);
|
speckleReceiver.OnReceiveProgressAction.AddListener(OnProgress);
|
||||||
commitObject = await speckleReceiver.ReceiveAsync(speckleReceiver.CancellationToken)
|
commitObject = await speckleReceiver
|
||||||
|
.ReceiveAsync(speckleReceiver.CancellationToken)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
Progress.Finish(transport);
|
Progress.Finish(transport);
|
||||||
Progress.Finish(deserialize);
|
Progress.Finish(deserialize);
|
||||||
}
|
}
|
||||||
catch(OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
Progress.Finish(transport, Progress.Status.Canceled);
|
Progress.Finish(transport, Progress.Status.Canceled);
|
||||||
Progress.Finish(deserialize, Progress.Status.Canceled);
|
Progress.Finish(deserialize, Progress.Status.Canceled);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
catch(Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
Progress.Finish(transport, Progress.Status.Failed);
|
Progress.Finish(transport, Progress.Status.Failed);
|
||||||
Progress.Finish(deserialize, Progress.Status.Failed);
|
Progress.Finish(deserialize, Progress.Status.Failed);
|
||||||
|
@ -287,12 +341,13 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
go.AddComponent<SpeckleReceiver>();
|
go.AddComponent<SpeckleReceiver>();
|
||||||
go.AddComponent<ReceiveFromURL>();
|
go.AddComponent<ReceiveFromURL>();
|
||||||
go.AddComponent<SpeckleSender>();
|
go.AddComponent<SpeckleSender>();
|
||||||
|
|
||||||
#if UNITY_2021_2_OR_NEWER
|
#if UNITY_2021_2_OR_NEWER
|
||||||
var icon = AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/systems.speckle.speckle-unity/Editor/Gizmos/logo128.png");
|
var icon = AssetDatabase.LoadAssetAtPath<Texture2D>(
|
||||||
|
"Packages/systems.speckle.speckle-unity/Editor/Gizmos/logo128.png"
|
||||||
|
);
|
||||||
EditorGUIUtility.SetIconForObject(go, icon);
|
EditorGUIUtility.SetIconForObject(go, icon);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,36 +12,40 @@ using Component = UnityEngine.Component;
|
||||||
#nullable enable
|
#nullable enable
|
||||||
namespace Speckle.ConnectorUnity.Components.Editor
|
namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
{
|
{
|
||||||
|
|
||||||
public enum SelectionFilter
|
public enum SelectionFilter
|
||||||
{
|
{
|
||||||
[Tooltip("Convert all children of this GameObject")]
|
[Tooltip("Convert all children of this GameObject")]
|
||||||
Children,
|
Children,
|
||||||
[Tooltip("Convert GameObjects currently selected in the hierarchy (consider padlocking this inspector)")]
|
|
||||||
|
[Tooltip(
|
||||||
|
"Convert GameObjects currently selected in the hierarchy (consider padlocking this inspector)"
|
||||||
|
)]
|
||||||
Selection,
|
Selection,
|
||||||
|
|
||||||
[InspectorName("All (excl. disabled)")]
|
[InspectorName("All (excl. disabled)")]
|
||||||
[Tooltip("Convert all GameObjects (excluding disabled) in the active scene")]
|
[Tooltip("Convert all GameObjects (excluding disabled) in the active scene")]
|
||||||
Enabled,
|
Enabled,
|
||||||
|
|
||||||
[Tooltip("Convert all GameObjects (including disabled) in the active scene")]
|
[Tooltip("Convert all GameObjects (including disabled) in the active scene")]
|
||||||
[InspectorName("All (incl. disabled)")]
|
[InspectorName("All (incl. disabled)")]
|
||||||
All,
|
All,
|
||||||
}
|
}
|
||||||
|
|
||||||
[CustomEditor(typeof(SpeckleSender))]
|
[CustomEditor(typeof(SpeckleSender))]
|
||||||
[CanEditMultipleObjects]
|
[CanEditMultipleObjects]
|
||||||
public class SpeckleSendEditor : UnityEditor.Editor
|
public class SpeckleSendEditor : UnityEditor.Editor
|
||||||
{
|
{
|
||||||
|
private SelectionFilter _selectedFilter = SelectionFilter.Children;
|
||||||
private SelectionFilter selectedFilter = SelectionFilter.Children;
|
|
||||||
|
|
||||||
public override async void OnInspectorGUI()
|
public override async void OnInspectorGUI()
|
||||||
{
|
{
|
||||||
//Draw events in a collapsed region
|
//Draw events in a collapsed region
|
||||||
DrawDefaultInspector();
|
DrawDefaultInspector();
|
||||||
|
|
||||||
bool shouldSend = GUILayout.Button("Send!");
|
bool shouldSend = GUILayout.Button("Send!");
|
||||||
selectedFilter = (SelectionFilter)EditorGUILayout.EnumPopup("Selection", selectedFilter);
|
_selectedFilter = (SelectionFilter)
|
||||||
|
EditorGUILayout.EnumPopup("Selection", _selectedFilter);
|
||||||
|
|
||||||
if (shouldSend)
|
if (shouldSend)
|
||||||
{
|
{
|
||||||
await ConvertAndSend();
|
await ConvertAndSend();
|
||||||
|
@ -50,30 +54,35 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
|
|
||||||
public async Task<string?> ConvertAndSend()
|
public async Task<string?> ConvertAndSend()
|
||||||
{
|
{
|
||||||
var speckleSender = (SpeckleSender) target;
|
var speckleSender = (SpeckleSender)target;
|
||||||
|
|
||||||
if (!speckleSender.GetSelection(out _, out _, out _, out string? error))
|
if (!speckleSender.GetSelection(out _, out _, out _, out string? error))
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"Not ready to send: {error}", speckleSender);
|
Debug.LogWarning($"Not ready to send: {error}", speckleSender);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
RecursiveConverter converter = speckleSender.Converter;
|
RecursiveConverter converter = speckleSender.Converter;
|
||||||
Base data = selectedFilter switch
|
Base data = _selectedFilter switch
|
||||||
{
|
{
|
||||||
SelectionFilter.All => ConvertAll(converter),
|
SelectionFilter.All => ConvertAll(converter),
|
||||||
SelectionFilter.Enabled => ConvertEnabled(converter),
|
SelectionFilter.Enabled => ConvertEnabled(converter),
|
||||||
SelectionFilter.Children => ConvertChildren(converter),
|
SelectionFilter.Children => ConvertChildren(converter),
|
||||||
SelectionFilter.Selection => ConvertSelection(converter),
|
SelectionFilter.Selection => ConvertSelection(converter),
|
||||||
_ => throw new InvalidEnumArgumentException(nameof(selectedFilter), (int) selectedFilter, selectedFilter.GetType()),
|
_
|
||||||
|
=> throw new InvalidEnumArgumentException(
|
||||||
|
nameof(_selectedFilter),
|
||||||
|
(int)_selectedFilter,
|
||||||
|
_selectedFilter.GetType()
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
//TODO onError action?
|
//TODO onError action?
|
||||||
if (data["@objects"] is IList l && l.Count == 0)
|
if (data["@objects"] is IList l && l.Count == 0)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"Nothing to send", speckleSender);
|
Debug.LogWarning($"Nothing to send", speckleSender);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return await speckleSender.SendDataAsync(data, true);
|
return await speckleSender.SendDataAsync(data, true);
|
||||||
}
|
}
|
||||||
|
@ -81,31 +90,36 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
private Base ConvertChildren(RecursiveConverter converter)
|
private Base ConvertChildren(RecursiveConverter converter)
|
||||||
{
|
{
|
||||||
return converter.RecursivelyConvertToSpeckle(
|
return converter.RecursivelyConvertToSpeckle(
|
||||||
new []{((Component)target).gameObject},
|
new[] { ((Component)target).gameObject },
|
||||||
_ => true);
|
_ => true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Base ConvertSelection(RecursiveConverter converter)
|
private Base ConvertSelection(RecursiveConverter converter)
|
||||||
{
|
{
|
||||||
ISet<GameObject> selection = Selection.GetFiltered<GameObject>(SelectionMode.Deep).ToImmutableHashSet();
|
ISet<GameObject> selection = Selection
|
||||||
|
.GetFiltered<GameObject>(SelectionMode.Deep)
|
||||||
|
.ToImmutableHashSet();
|
||||||
return converter.RecursivelyConvertToSpeckle(
|
return converter.RecursivelyConvertToSpeckle(
|
||||||
SceneManager.GetActiveScene().GetRootGameObjects(),
|
SceneManager.GetActiveScene().GetRootGameObjects(),
|
||||||
go => selection.Contains(go));
|
go => selection.Contains(go)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Base ConvertAll(RecursiveConverter converter)
|
private Base ConvertAll(RecursiveConverter converter)
|
||||||
{
|
{
|
||||||
return converter.RecursivelyConvertToSpeckle(
|
return converter.RecursivelyConvertToSpeckle(
|
||||||
SceneManager.GetActiveScene().GetRootGameObjects(),
|
SceneManager.GetActiveScene().GetRootGameObjects(),
|
||||||
_ => true);
|
_ => true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Base ConvertEnabled(RecursiveConverter converter)
|
private Base ConvertEnabled(RecursiveConverter converter)
|
||||||
{
|
{
|
||||||
return converter.RecursivelyConvertToSpeckle(
|
return converter.RecursivelyConvertToSpeckle(
|
||||||
SceneManager.GetActiveScene().GetRootGameObjects(),
|
SceneManager.GetActiveScene().GetRootGameObjects(),
|
||||||
go => go.activeInHierarchy);
|
go => go.activeInHierarchy
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,10 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
public class StreamManagerEditor : UnityEditor.Editor
|
public class StreamManagerEditor : UnityEditor.Editor
|
||||||
{
|
{
|
||||||
private bool _foldOutAccount;
|
private bool _foldOutAccount;
|
||||||
private int _totalChildrenCount = 0;
|
private int _totalChildrenCount;
|
||||||
private StreamManager _streamManager;
|
private StreamManager _streamManager;
|
||||||
|
|
||||||
private static bool generateAssets;
|
private static bool _generateAssets;
|
||||||
|
|
||||||
public int StreamsLimit { get; set; } = 30;
|
public int StreamsLimit { get; set; } = 30;
|
||||||
public int BranchesLimit { get; set; } = 75;
|
public int BranchesLimit { get; set; } = 75;
|
||||||
|
@ -98,7 +98,6 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
private List<Branch> Branches
|
private List<Branch> Branches
|
||||||
{
|
{
|
||||||
get => _streamManager.Branches;
|
get => _streamManager.Branches;
|
||||||
|
|
||||||
set => _streamManager.Branches = value;
|
set => _streamManager.Branches = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +141,11 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
SelectedStream = Streams[i];
|
SelectedStream = Streams[i];
|
||||||
|
|
||||||
EditorUtility.DisplayProgressBar("Loading stream details...", "", 0);
|
EditorUtility.DisplayProgressBar("Loading stream details...", "", 0);
|
||||||
Branches = await Client.StreamGetBranches(SelectedStream.id, BranchesLimit, CommitsLimit);
|
Branches = await Client.StreamGetBranches(
|
||||||
|
SelectedStream.id,
|
||||||
|
BranchesLimit,
|
||||||
|
CommitsLimit
|
||||||
|
);
|
||||||
if (Branches.Any())
|
if (Branches.Any())
|
||||||
{
|
{
|
||||||
SelectedBranchIndex = 0;
|
SelectedBranchIndex = 0;
|
||||||
|
@ -155,7 +158,6 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
EditorUtility.ClearProgressBar();
|
EditorUtility.ClearProgressBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private async Task Receive()
|
private async Task Receive()
|
||||||
{
|
{
|
||||||
var transport = new ServerTransport(SelectedAccount, SelectedStream.id);
|
var transport = new ServerTransport(SelectedAccount, SelectedStream.id);
|
||||||
|
@ -163,53 +165,82 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Commit selectedCommit = Branches[SelectedBranchIndex].commits.items[SelectedCommitIndex];
|
Commit selectedCommit = Branches[SelectedBranchIndex].commits.items[
|
||||||
|
SelectedCommitIndex
|
||||||
|
];
|
||||||
// Receive Speckle Objects
|
// Receive Speckle Objects
|
||||||
var @base = await Operations.Receive(
|
var @base = await Operations.Receive(
|
||||||
selectedCommit.referencedObject,
|
selectedCommit.referencedObject,
|
||||||
remoteTransport: transport,
|
remoteTransport: transport,
|
||||||
onProgressAction: dict =>
|
onProgressAction: dict =>
|
||||||
{
|
{
|
||||||
UnityEditor.EditorApplication.delayCall += () =>
|
EditorApplication.delayCall += () =>
|
||||||
{
|
{
|
||||||
EditorUtility.DisplayProgressBar($"Receiving data from {transport.BaseUri}...", "",
|
EditorUtility.DisplayProgressBar(
|
||||||
Convert.ToSingle(dict.Values.Average() / _totalChildrenCount));
|
$"Receiving data from {transport.BaseUri}...",
|
||||||
|
"",
|
||||||
|
Convert.ToSingle(dict.Values.Average() / _totalChildrenCount)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onTotalChildrenCountKnown: count => { _totalChildrenCount = count; }
|
onTotalChildrenCountKnown: count =>
|
||||||
|
{
|
||||||
|
_totalChildrenCount = count;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
if (@base is null)
|
||||||
|
throw new InvalidOperationException("Received object was null");
|
||||||
|
|
||||||
EditorUtility.ClearProgressBar();
|
EditorUtility.ClearProgressBar();
|
||||||
|
|
||||||
Analytics.TrackEvent(SelectedAccount, Analytics.Events.Receive, new Dictionary<string, object>()
|
Analytics.TrackEvent(
|
||||||
{
|
SelectedAccount,
|
||||||
{"mode", nameof(StreamManagerEditor)},
|
Analytics.Events.Receive,
|
||||||
{"sourceHostApp", HostApplications.GetHostAppFromString(selectedCommit.sourceApplication).Slug},
|
new Dictionary<string, object>()
|
||||||
{"sourceHostAppVersion", selectedCommit.sourceApplication ?? ""},
|
{
|
||||||
{"hostPlatform", Application.platform.ToString()},
|
{ "mode", nameof(StreamManagerEditor) },
|
||||||
{"isMultiplayer", selectedCommit.authorId != SelectedAccount.userInfo.id},
|
{
|
||||||
});
|
"sourceHostApp",
|
||||||
|
HostApplications
|
||||||
|
.GetHostAppFromString(selectedCommit.sourceApplication)
|
||||||
|
.Slug
|
||||||
|
},
|
||||||
|
{ "sourceHostAppVersion", selectedCommit.sourceApplication ?? "" },
|
||||||
|
{ "hostPlatform", Application.platform.ToString() },
|
||||||
|
{ "isMultiplayer", selectedCommit.authorId != SelectedAccount.userInfo.id },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
//Convert Speckle Objects
|
//Convert Speckle Objects
|
||||||
int childrenConverted = 0;
|
int childrenConverted = 0;
|
||||||
|
|
||||||
void BeforeConvertCallback(Base b)
|
void BeforeConvertCallback(Base b)
|
||||||
{
|
{
|
||||||
EditorUtility.DisplayProgressBar("Converting To Native...", $"{b.speckle_type} - {b.id}",
|
EditorUtility.DisplayProgressBar(
|
||||||
Convert.ToSingle(childrenConverted++ / _totalChildrenCount));
|
"Converting To Native...",
|
||||||
|
$"{b.speckle_type} - {b.id}",
|
||||||
|
Convert.ToSingle(childrenConverted++ / _totalChildrenCount)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var go = _streamManager.ConvertRecursivelyToNative(@base,
|
_streamManager.ConvertRecursivelyToNative(
|
||||||
Branches[SelectedBranchIndex].commits.items[SelectedCommitIndex].id, BeforeConvertCallback);
|
@base,
|
||||||
|
Branches[SelectedBranchIndex].commits.items[SelectedCommitIndex].id,
|
||||||
|
BeforeConvertCallback
|
||||||
|
);
|
||||||
|
|
||||||
// Read Receipt
|
// Read Receipt
|
||||||
await Client.CommitReceived(new CommitReceivedInput
|
await Client.CommitReceived(
|
||||||
{
|
new CommitReceivedInput
|
||||||
streamId = SelectedStream.id,
|
{
|
||||||
commitId = Branches[SelectedBranchIndex].commits.items[SelectedCommitIndex].id,
|
streamId = SelectedStream.id,
|
||||||
message = $"received commit from {HostApplications.Unity.Name} Editor",
|
commitId = Branches[SelectedBranchIndex].commits.items[
|
||||||
sourceApplication = HostApplications.Unity.Name
|
SelectedCommitIndex
|
||||||
});
|
].id,
|
||||||
|
message = $"received commit from {HostApplications.Unity.Name} Editor",
|
||||||
|
sourceApplication = HostApplications.Unity.Name
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -223,8 +254,7 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
|
|
||||||
public override async void OnInspectorGUI()
|
public override async void OnInspectorGUI()
|
||||||
{
|
{
|
||||||
_streamManager = (StreamManager) target;
|
_streamManager = (StreamManager)target;
|
||||||
|
|
||||||
|
|
||||||
#region Account GUI
|
#region Account GUI
|
||||||
|
|
||||||
|
@ -234,12 +264,15 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
|
||||||
SelectedAccountIndex = EditorGUILayout.Popup("Accounts", SelectedAccountIndex,
|
SelectedAccountIndex = EditorGUILayout.Popup(
|
||||||
|
"Accounts",
|
||||||
|
SelectedAccountIndex,
|
||||||
Accounts.Select(x => x.userInfo.email + " | " + x.serverInfo.name).ToArray(),
|
Accounts.Select(x => x.userInfo.email + " | " + x.serverInfo.name).ToArray(),
|
||||||
GUILayout.ExpandWidth(true), GUILayout.Height(20));
|
GUILayout.ExpandWidth(true),
|
||||||
|
GUILayout.Height(20)
|
||||||
|
);
|
||||||
|
|
||||||
if (OldSelectedAccountIndex != SelectedAccountIndex)
|
if (OldSelectedAccountIndex != SelectedAccountIndex)
|
||||||
{
|
{
|
||||||
|
@ -255,26 +288,37 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
|
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
|
||||||
#region Speckle Account Info
|
#region Speckle Account Info
|
||||||
|
|
||||||
_foldOutAccount = EditorGUILayout.BeginFoldoutHeaderGroup(_foldOutAccount, "Account Info");
|
_foldOutAccount = EditorGUILayout.BeginFoldoutHeaderGroup(
|
||||||
|
_foldOutAccount,
|
||||||
|
"Account Info"
|
||||||
|
);
|
||||||
|
|
||||||
if (_foldOutAccount)
|
if (_foldOutAccount)
|
||||||
{
|
{
|
||||||
EditorGUI.BeginDisabledGroup(true);
|
EditorGUI.BeginDisabledGroup(true);
|
||||||
|
|
||||||
EditorGUILayout.TextField("Name", SelectedAccount.userInfo.name,
|
EditorGUILayout.TextField(
|
||||||
|
"Name",
|
||||||
|
SelectedAccount.userInfo.name,
|
||||||
GUILayout.Height(20),
|
GUILayout.Height(20),
|
||||||
GUILayout.ExpandWidth(true));
|
GUILayout.ExpandWidth(true)
|
||||||
|
);
|
||||||
|
|
||||||
EditorGUILayout.TextField("Server", SelectedAccount.serverInfo.name,
|
EditorGUILayout.TextField(
|
||||||
|
"Server",
|
||||||
|
SelectedAccount.serverInfo.name,
|
||||||
GUILayout.Height(20),
|
GUILayout.Height(20),
|
||||||
GUILayout.ExpandWidth(true));
|
GUILayout.ExpandWidth(true)
|
||||||
|
);
|
||||||
|
|
||||||
EditorGUILayout.TextField("URL", SelectedAccount.serverInfo.url,
|
EditorGUILayout.TextField(
|
||||||
|
"URL",
|
||||||
|
SelectedAccount.serverInfo.url,
|
||||||
GUILayout.Height(20),
|
GUILayout.Height(20),
|
||||||
GUILayout.ExpandWidth(true));
|
GUILayout.ExpandWidth(true)
|
||||||
|
);
|
||||||
|
|
||||||
EditorGUI.EndDisabledGroup();
|
EditorGUI.EndDisabledGroup();
|
||||||
}
|
}
|
||||||
|
@ -292,9 +336,13 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
|
||||||
SelectedStreamIndex = EditorGUILayout.Popup("Streams",
|
SelectedStreamIndex = EditorGUILayout.Popup(
|
||||||
SelectedStreamIndex, Streams.Select(x => x.name).ToArray(), GUILayout.Height(20),
|
"Streams",
|
||||||
GUILayout.ExpandWidth(true));
|
SelectedStreamIndex,
|
||||||
|
Streams.Select(x => x.name).ToArray(),
|
||||||
|
GUILayout.Height(20),
|
||||||
|
GUILayout.ExpandWidth(true)
|
||||||
|
);
|
||||||
|
|
||||||
if (OldSelectedStreamIndex != SelectedStreamIndex)
|
if (OldSelectedStreamIndex != SelectedStreamIndex)
|
||||||
{
|
{
|
||||||
|
@ -319,23 +367,29 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
|
||||||
SelectedBranchIndex = EditorGUILayout.Popup("Branches",
|
SelectedBranchIndex = EditorGUILayout.Popup(
|
||||||
SelectedBranchIndex, Branches.Select(x => x.name).ToArray(), GUILayout.Height(20),
|
"Branches",
|
||||||
GUILayout.ExpandWidth(true));
|
SelectedBranchIndex,
|
||||||
|
Branches.Select(x => x.name).ToArray(),
|
||||||
|
GUILayout.Height(20),
|
||||||
|
GUILayout.ExpandWidth(true)
|
||||||
|
);
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
|
||||||
if (!Branches[SelectedBranchIndex].commits.items.Any())
|
if (!Branches[SelectedBranchIndex].commits.items.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
|
||||||
SelectedCommitIndex = EditorGUILayout.Popup("Commits",
|
SelectedCommitIndex = EditorGUILayout.Popup(
|
||||||
|
"Commits",
|
||||||
SelectedCommitIndex,
|
SelectedCommitIndex,
|
||||||
Branches[SelectedBranchIndex].commits.items.Select(x => $"{x.message} - {x.id}").ToArray(),
|
Branches[SelectedBranchIndex].commits.items
|
||||||
|
.Select(x => $"{x.message} - {x.id}")
|
||||||
|
.ToArray(),
|
||||||
GUILayout.Height(20),
|
GUILayout.Height(20),
|
||||||
GUILayout.ExpandWidth(true));
|
GUILayout.ExpandWidth(true)
|
||||||
|
);
|
||||||
|
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
@ -347,12 +401,12 @@ namespace Speckle.ConnectorUnity.Components.Editor
|
||||||
|
|
||||||
GUILayout.Label("Generate assets");
|
GUILayout.Label("Generate assets");
|
||||||
GUILayout.FlexibleSpace();
|
GUILayout.FlexibleSpace();
|
||||||
bool selection = GUILayout.Toggle(generateAssets, "");
|
bool selection = GUILayout.Toggle(_generateAssets, "");
|
||||||
if (generateAssets != selection)
|
if (_generateAssets != selection)
|
||||||
{
|
{
|
||||||
|
_generateAssets = selection;
|
||||||
generateAssets = selection;
|
_streamManager.RC.AssetCache.nativeCaches =
|
||||||
_streamManager.RC.AssetCache.nativeCaches = NativeCacheFactory.GetDefaultNativeCacheSetup(generateAssets);
|
NativeCacheFactory.GetDefaultNativeCacheSetup(_generateAssets);
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using Speckle.Core.Models;
|
using Speckle.Core.Models;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
@ -18,23 +16,28 @@ namespace Speckle.ConnectorUnity.NativeCache.Editor
|
||||||
public const string DefaultPath = "Assets/Resources";
|
public const string DefaultPath = "Assets/Resources";
|
||||||
public string path = DefaultPath;
|
public string path = DefaultPath;
|
||||||
|
|
||||||
private MemoryNativeCache readCache;
|
private MemoryNativeCache _readCache;
|
||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
void Awake()
|
void Awake()
|
||||||
{
|
{
|
||||||
readCache = CreateInstance<MemoryNativeCache>();
|
_readCache = CreateInstance<MemoryNativeCache>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool TryGetObject<T>(Base speckleObject, [NotNullWhen(true)] out T? nativeObject) where T : class
|
public override bool TryGetObject<T>(
|
||||||
|
Base speckleObject,
|
||||||
|
[NotNullWhen(true)] out T? nativeObject
|
||||||
|
)
|
||||||
|
where T : class
|
||||||
{
|
{
|
||||||
if(readCache.TryGetObject(speckleObject, out nativeObject))
|
if (_readCache.TryGetObject(speckleObject, out nativeObject))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Type nativeType = typeof(T);
|
Type nativeType = typeof(T);
|
||||||
if (!GetAssetPath(nativeType, speckleObject, out string? assetPath)) return false;
|
if (!GetAssetPath(nativeType, speckleObject, out string? assetPath))
|
||||||
|
return false;
|
||||||
|
|
||||||
nativeObject = AssetDatabase.LoadAssetAtPath<T>(assetPath);
|
nativeObject = AssetDatabase.LoadAssetAtPath<T>(assetPath);
|
||||||
return nativeObject != null;
|
return nativeObject != null;
|
||||||
}
|
}
|
||||||
|
@ -43,32 +46,39 @@ namespace Speckle.ConnectorUnity.NativeCache.Editor
|
||||||
{
|
{
|
||||||
return WriteObject(speckleObject, nativeObject);
|
return WriteObject(speckleObject, nativeObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool WriteObject(Base speckleObject, Object nativeObject)
|
private bool WriteObject(Base speckleObject, Object nativeObject)
|
||||||
{
|
{
|
||||||
Type nativeType = nativeObject.GetType();
|
Type nativeType = nativeObject.GetType();
|
||||||
if (!GetAssetPath(nativeType, speckleObject, out string? assetPath)) return false;
|
if (!GetAssetPath(nativeType, speckleObject, out string? assetPath))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Special case for GameObjects, we want to use PrefabUtility
|
// Special case for GameObjects, we want to use PrefabUtility
|
||||||
if (nativeObject is GameObject go)
|
if (nativeObject is GameObject go)
|
||||||
{
|
{
|
||||||
var prefab = PrefabUtility.SaveAsPrefabAssetAndConnect(go, assetPath, InteractionMode.AutomatedAction);
|
var prefab = PrefabUtility.SaveAsPrefabAssetAndConnect(
|
||||||
return readCache.TrySaveObject(speckleObject, prefab);
|
go,
|
||||||
|
assetPath,
|
||||||
|
InteractionMode.AutomatedAction
|
||||||
|
);
|
||||||
|
return _readCache.TrySaveObject(speckleObject, prefab);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exit early if there's already an asset
|
// Exit early if there's already an asset
|
||||||
Object? existing = AssetDatabase.LoadAssetAtPath(assetPath, nativeObject.GetType());
|
Object? existing = AssetDatabase.LoadAssetAtPath(assetPath, nativeObject.GetType());
|
||||||
if (existing != null)
|
if (existing != null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"Failed to write asset as one already existed at path: {assetPath}", this);
|
Debug.LogWarning(
|
||||||
|
$"Failed to write asset as one already existed at path: {assetPath}",
|
||||||
|
this
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetDatabase.CreateAsset(nativeObject, $"{assetPath}");
|
AssetDatabase.CreateAsset(nativeObject, $"{assetPath}");
|
||||||
return readCache.TrySaveObject(speckleObject, nativeObject);
|
return _readCache.TrySaveObject(speckleObject, nativeObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void BeginWrite()
|
public override void BeginWrite()
|
||||||
{
|
{
|
||||||
base.BeginWrite();
|
base.BeginWrite();
|
||||||
|
@ -77,32 +87,40 @@ namespace Speckle.ConnectorUnity.NativeCache.Editor
|
||||||
|
|
||||||
public override void FinishWrite()
|
public override void FinishWrite()
|
||||||
{
|
{
|
||||||
if (!isWriting) return;
|
if (!isWriting)
|
||||||
|
return;
|
||||||
//AssetDatabase.StopAssetEditing();
|
//AssetDatabase.StopAssetEditing();
|
||||||
AssetDatabase.SaveAssets();
|
AssetDatabase.SaveAssets();
|
||||||
|
|
||||||
if (readCache != null) readCache.LoadedAssets.Clear();
|
if (_readCache != null)
|
||||||
|
_readCache.LoadedAssets.Clear();
|
||||||
|
|
||||||
base.FinishWrite();
|
base.FinishWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool GetAssetPath(Type nativeType, Base speckleObject, [NotNullWhen(true)] out string? outPath)
|
private bool GetAssetPath(
|
||||||
|
Type nativeType,
|
||||||
|
Base speckleObject,
|
||||||
|
[NotNullWhen(true)] out string? outPath
|
||||||
|
)
|
||||||
{
|
{
|
||||||
string? folder = AssetHelpers.GetAssetFolder(nativeType, path);
|
string? folder = AssetHelpers.GetAssetFolder(nativeType, path);
|
||||||
outPath = null;
|
outPath = null;
|
||||||
if (folder == null) return false;
|
if (folder == null)
|
||||||
if (!CreateDirectory(folder)) return false;
|
return false;
|
||||||
|
if (!CreateDirectory(folder))
|
||||||
|
return false;
|
||||||
|
|
||||||
string assetName = AssetHelpers.GetAssetName(speckleObject, nativeType);
|
string assetName = AssetHelpers.GetAssetName(speckleObject, nativeType);
|
||||||
outPath = $"{folder}/{assetName}";
|
outPath = $"{folder}/{assetName}";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool CreateDirectory(string directoryPath)
|
private static bool CreateDirectory(string directoryPath)
|
||||||
{
|
{
|
||||||
if (Directory.Exists(directoryPath))
|
if (Directory.Exists(directoryPath))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
var info = Directory.CreateDirectory(directoryPath);
|
var info = Directory.CreateDirectory(directoryPath);
|
||||||
AssetDatabase.Refresh();
|
AssetDatabase.Refresh();
|
||||||
return info.Exists;
|
return info.Exists;
|
||||||
|
@ -111,16 +129,20 @@ namespace Speckle.ConnectorUnity.NativeCache.Editor
|
||||||
[ContextMenu("SetPath")]
|
[ContextMenu("SetPath")]
|
||||||
public void SetPath_Menu()
|
public void SetPath_Menu()
|
||||||
{
|
{
|
||||||
var selection = EditorUtility.OpenFolderPanel("Set Assets Path", "Assets/Resources", "");
|
var selection = EditorUtility.OpenFolderPanel(
|
||||||
|
"Set Assets Path",
|
||||||
if (selection.StartsWith(Application.dataPath)) {
|
"Assets/Resources",
|
||||||
|
""
|
||||||
|
);
|
||||||
|
|
||||||
|
if (selection.StartsWith(Application.dataPath))
|
||||||
|
{
|
||||||
path = "Assets" + selection.Substring(Application.dataPath.Length);
|
path = "Assets" + selection.Substring(Application.dataPath.Length);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogError($"Expected selection to be within {Application.dataPath}");
|
Debug.LogError($"Expected selection to be within {Application.dataPath}");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,10 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection.Editor
|
||||||
public sealed class AccountSelectionDrawer : OptionSelectionDrawer<Account>
|
public sealed class AccountSelectionDrawer : OptionSelectionDrawer<Account>
|
||||||
{
|
{
|
||||||
protected override bool DisplayRefresh => true;
|
protected override bool DisplayRefresh => true;
|
||||||
protected override string FormatOption(Account o) => $"{o.userInfo.email} | {o.serverInfo.name}";
|
|
||||||
|
protected override string FormatOption(Account o) =>
|
||||||
|
$"{o.userInfo.email} | {o.serverInfo.name}";
|
||||||
|
|
||||||
public AccountSelectionDrawer()
|
public AccountSelectionDrawer()
|
||||||
{
|
{
|
||||||
details = new (string, Func<Account, string>)[]
|
details = new (string, Func<Account, string>)[]
|
||||||
|
@ -29,17 +31,18 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection.Editor
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[CustomPropertyDrawer(typeof(StreamSelection))]
|
[CustomPropertyDrawer(typeof(StreamSelection))]
|
||||||
public sealed class StreamSelectionDrawer : OptionSelectionDrawer<Stream>
|
public sealed class StreamSelectionDrawer : OptionSelectionDrawer<Stream>
|
||||||
{
|
{
|
||||||
protected override bool DisplayRefresh => true;
|
protected override bool DisplayRefresh => true;
|
||||||
|
|
||||||
protected override string FormatOption(Stream o) => $"{o.name}";
|
protected override string FormatOption(Stream o) => $"{o.name}";
|
||||||
|
|
||||||
public StreamSelectionDrawer()
|
public StreamSelectionDrawer()
|
||||||
{
|
{
|
||||||
properties = new []{$"<{nameof(StreamSelection.StreamsLimit)}>k__BackingField"};
|
properties = new[] { $"<{nameof(StreamSelection.StreamsLimit)}>k__BackingField" };
|
||||||
|
|
||||||
details = new (string, Func<Stream, string>)[]
|
details = new (string, Func<Stream, string>)[]
|
||||||
{
|
{
|
||||||
("Stream id", s => s.id),
|
("Stream id", s => s.id),
|
||||||
|
@ -51,33 +54,31 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection.Editor
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[CustomPropertyDrawer(typeof(BranchSelection))]
|
[CustomPropertyDrawer(typeof(BranchSelection))]
|
||||||
public sealed class BranchSelectionDrawer : OptionSelectionDrawer<Branch>
|
public sealed class BranchSelectionDrawer : OptionSelectionDrawer<Branch>
|
||||||
{
|
{
|
||||||
protected override bool DisplayRefresh => true;
|
protected override bool DisplayRefresh => true;
|
||||||
|
|
||||||
protected override string FormatOption(Branch o) => $"{o.name}";
|
protected override string FormatOption(Branch o) => $"{o.name}";
|
||||||
|
|
||||||
public BranchSelectionDrawer()
|
public BranchSelectionDrawer()
|
||||||
{
|
{
|
||||||
properties = new []
|
properties = new[]
|
||||||
{
|
{
|
||||||
$"<{nameof(BranchSelection.BranchesLimit)}>k__BackingField",
|
$"<{nameof(BranchSelection.BranchesLimit)}>k__BackingField",
|
||||||
$"<{nameof(BranchSelection.CommitsLimit)}>k__BackingField",
|
$"<{nameof(BranchSelection.CommitsLimit)}>k__BackingField",
|
||||||
};
|
};
|
||||||
|
|
||||||
details = new (string, Func<Branch, string>)[]
|
details = new (string, Func<Branch, string>)[] { ("Description", s => s.description), };
|
||||||
{
|
|
||||||
("Description", s => s.description),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[CustomPropertyDrawer(typeof(CommitSelection))]
|
[CustomPropertyDrawer(typeof(CommitSelection))]
|
||||||
public sealed class CommitSelectionDrawer : OptionSelectionDrawer<Commit>
|
public sealed class CommitSelectionDrawer : OptionSelectionDrawer<Commit>
|
||||||
{
|
{
|
||||||
protected override string FormatOption(Commit o) => $"{o.message} - {o.id}";
|
protected override string FormatOption(Commit o) => $"{o.message} - {o.id}";
|
||||||
|
|
||||||
public CommitSelectionDrawer()
|
public CommitSelectionDrawer()
|
||||||
{
|
{
|
||||||
details = new (string, Func<Commit, string>)[]
|
details = new (string, Func<Commit, string>)[]
|
||||||
|
@ -90,13 +91,14 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection.Editor
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract class OptionSelectionDrawer<TOption> : PropertyDrawer
|
||||||
public abstract class OptionSelectionDrawer<TOption> : PropertyDrawer where TOption : class
|
where TOption : class
|
||||||
{
|
{
|
||||||
private const float RefreshButtonWidthScale = 0.2f;
|
private const float RefreshButtonWidthScale = 0.2f;
|
||||||
private const float PrefixIndentation = 100f;
|
private const float PrefixIndentation = 100f;
|
||||||
protected readonly float DetailsTextHeight = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
|
protected readonly float DetailsTextHeight =
|
||||||
|
EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
|
||||||
|
|
||||||
protected virtual bool DisplayRefresh => false;
|
protected virtual bool DisplayRefresh => false;
|
||||||
protected abstract string FormatOption(TOption o);
|
protected abstract string FormatOption(TOption o);
|
||||||
|
@ -105,7 +107,7 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection.Editor
|
||||||
protected string[] properties = { };
|
protected string[] properties = { };
|
||||||
|
|
||||||
protected (string, Func<TOption, string>)[] details = { };
|
protected (string, Func<TOption, string>)[] details = { };
|
||||||
|
|
||||||
private string[] GetFormattedOptions(TOption[] options)
|
private string[] GetFormattedOptions(TOption[] options)
|
||||||
{
|
{
|
||||||
int optionsCount = options.Length;
|
int optionsCount = options.Length;
|
||||||
|
@ -118,7 +120,12 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection.Editor
|
||||||
return choices;
|
return choices;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnGUIDetails(Rect position, SerializedProperty property, GUIContent label, TOption? selection)
|
protected virtual void OnGUIDetails(
|
||||||
|
Rect position,
|
||||||
|
SerializedProperty property,
|
||||||
|
GUIContent label,
|
||||||
|
TOption? selection
|
||||||
|
)
|
||||||
{
|
{
|
||||||
position.height = DetailsTextHeight;
|
position.height = DetailsTextHeight;
|
||||||
|
|
||||||
|
@ -142,80 +149,106 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection.Editor
|
||||||
EditorGUI.EndDisabledGroup();
|
EditorGUI.EndDisabledGroup();
|
||||||
EditorGUI.indentLevel--;
|
EditorGUI.indentLevel--;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||||
{
|
{
|
||||||
EditorGUI.BeginProperty(position, label, property);
|
EditorGUI.BeginProperty(position, label, property);
|
||||||
var t = (OptionSelection<TOption>)fieldInfo.GetValue(property.serializedObject.targetObject);
|
var t =
|
||||||
|
(OptionSelection<TOption>)
|
||||||
|
fieldInfo.GetValue(property.serializedObject.targetObject);
|
||||||
|
|
||||||
var selectionRect = position;
|
var selectionRect = position;
|
||||||
selectionRect.x += PrefixIndentation + 5;
|
selectionRect.x += PrefixIndentation + 5;
|
||||||
selectionRect.width -= PrefixIndentation + 5;
|
selectionRect.width -= PrefixIndentation + 5;
|
||||||
|
|
||||||
TOption? selectedOption = t.Selected;
|
TOption? selectedOption = t.Selected;
|
||||||
|
|
||||||
// Options selection
|
// Options selection
|
||||||
{
|
{
|
||||||
|
|
||||||
var popupSize = DisplayRefresh
|
var popupSize = DisplayRefresh
|
||||||
? new Rect(selectionRect.x, selectionRect.y, selectionRect.width * (1-RefreshButtonWidthScale), DetailsTextHeight)
|
? new Rect(
|
||||||
|
selectionRect.x,
|
||||||
|
selectionRect.y,
|
||||||
|
selectionRect.width * (1 - RefreshButtonWidthScale),
|
||||||
|
DetailsTextHeight
|
||||||
|
)
|
||||||
: selectionRect;
|
: selectionRect;
|
||||||
|
|
||||||
string selectedChoice = selectedOption != null ? FormatOption(selectedOption) : "";
|
string selectedChoice = selectedOption != null ? FormatOption(selectedOption) : "";
|
||||||
|
|
||||||
if (GUI.Button(popupSize, selectedChoice, EditorStyles.popup))
|
if (GUI.Button(popupSize, selectedChoice, EditorStyles.popup))
|
||||||
{
|
{
|
||||||
var windowPos = GUIUtility.GUIToScreenPoint(Event.current.mousePosition);
|
var windowPos = GUIUtility.GUIToScreenPoint(Event.current.mousePosition);
|
||||||
var provider = ScriptableObject.CreateInstance<StringListSearchProvider>();
|
var provider = ScriptableObject.CreateInstance<StringListSearchProvider>();
|
||||||
provider.Title = typeof(TOption).Name;
|
provider.Title = typeof(TOption).Name;
|
||||||
provider.listItems = GetFormattedOptions(t.Options);;
|
provider.listItems = GetFormattedOptions(t.Options);
|
||||||
provider.onSetIndexCallback = o => { t.SelectedIndex = o;};
|
;
|
||||||
|
provider.onSetIndexCallback = o =>
|
||||||
|
{
|
||||||
|
t.SelectedIndex = o;
|
||||||
|
};
|
||||||
SearchWindow.Open(new SearchWindowContext(windowPos), provider);
|
SearchWindow.Open(new SearchWindowContext(windowPos), provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional refresh
|
// Optional refresh
|
||||||
if (DisplayRefresh)
|
if (DisplayRefresh)
|
||||||
{
|
{
|
||||||
var buttonSize = new Rect(selectionRect.x + popupSize.width , selectionRect.y, selectionRect.width * RefreshButtonWidthScale, DetailsTextHeight);
|
var buttonSize = new Rect(
|
||||||
|
selectionRect.x + popupSize.width,
|
||||||
|
selectionRect.y,
|
||||||
|
selectionRect.width * RefreshButtonWidthScale,
|
||||||
|
DetailsTextHeight
|
||||||
|
);
|
||||||
if (GUI.Button(buttonSize, "Refresh"))
|
if (GUI.Button(buttonSize, "Refresh"))
|
||||||
{
|
{
|
||||||
EditorApplication.delayCall += t.RefreshOptions;
|
EditorApplication.delayCall += t.RefreshOptions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collapsable details
|
// Collapsable details
|
||||||
{
|
{
|
||||||
int visiblePropCount = property.isExpanded ? GUIDetailsPropertyCount : 0;
|
int visiblePropCount = property.isExpanded ? GUIDetailsPropertyCount : 0;
|
||||||
var detailsHeight = new Vector2(PrefixIndentation, DetailsTextHeight + visiblePropCount * DetailsTextHeight);
|
var detailsHeight = new Vector2(
|
||||||
var foldoutRect = new Rect(position.position, detailsHeight);
|
PrefixIndentation,
|
||||||
property.isExpanded = EditorGUI.BeginFoldoutHeaderGroup(foldoutRect, property.isExpanded, label);
|
DetailsTextHeight + visiblePropCount * DetailsTextHeight
|
||||||
|
);
|
||||||
|
var foldoutRect = new Rect(position.position, detailsHeight);
|
||||||
|
property.isExpanded = EditorGUI.BeginFoldoutHeaderGroup(
|
||||||
|
foldoutRect,
|
||||||
|
property.isExpanded,
|
||||||
|
label
|
||||||
|
);
|
||||||
if (property.isExpanded)
|
if (property.isExpanded)
|
||||||
{
|
{
|
||||||
OnGUIDetails(position, property, label, selectedOption);
|
OnGUIDetails(position, property, label, selectedOption);
|
||||||
}
|
}
|
||||||
EditorGUI.EndFoldoutHeaderGroup();
|
EditorGUI.EndFoldoutHeaderGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EditorGUI.EndProperty();
|
EditorGUI.EndProperty();
|
||||||
//EditorUtility.SetDirty(property.serializedObject.targetObject);
|
//EditorUtility.SetDirty(property.serializedObject.targetObject);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||||
{
|
{
|
||||||
var standardHeight = EditorGUIUtility.singleLineHeight;
|
var standardHeight = EditorGUIUtility.singleLineHeight;
|
||||||
|
|
||||||
if (!property.isExpanded) return standardHeight + EditorGUIUtility.standardVerticalSpacing;
|
|
||||||
|
|
||||||
var detailsHeight = GUIDetailsPropertyCount * (standardHeight + EditorGUIUtility.standardVerticalSpacing);
|
if (!property.isExpanded)
|
||||||
|
return standardHeight + EditorGUIUtility.standardVerticalSpacing;
|
||||||
return standardHeight + detailsHeight + EditorGUIUtility.standardVerticalSpacing + EditorGUIUtility.standardVerticalSpacing;
|
|
||||||
|
var detailsHeight =
|
||||||
|
GUIDetailsPropertyCount
|
||||||
|
* (standardHeight + EditorGUIUtility.standardVerticalSpacing);
|
||||||
|
|
||||||
|
return standardHeight
|
||||||
|
+ detailsHeight
|
||||||
|
+ EditorGUIUtility.standardVerticalSpacing
|
||||||
|
+ EditorGUIUtility.standardVerticalSpacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
public sealed class StringListSearchProvider : ScriptableObject, ISearchWindowProvider
|
public sealed class StringListSearchProvider : ScriptableObject, ISearchWindowProvider
|
||||||
{
|
{
|
||||||
|
@ -223,12 +256,13 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection.Editor
|
||||||
public string[] listItems;
|
public string[] listItems;
|
||||||
|
|
||||||
public Action<int> onSetIndexCallback;
|
public Action<int> onSetIndexCallback;
|
||||||
|
|
||||||
public List<SearchTreeEntry> CreateSearchTree(SearchWindowContext context)
|
public List<SearchTreeEntry> CreateSearchTree(SearchWindowContext context)
|
||||||
{
|
{
|
||||||
List<SearchTreeEntry> searchList = new(listItems.Length + 1) {new SearchTreeGroupEntry(new GUIContent(Title), 0)};
|
List<SearchTreeEntry> searchList =
|
||||||
|
new(listItems.Length + 1) { new SearchTreeGroupEntry(new GUIContent(Title), 0) };
|
||||||
for(int i = 0; i < listItems.Length; i++)
|
|
||||||
|
for (int i = 0; i < listItems.Length; i++)
|
||||||
{
|
{
|
||||||
SearchTreeEntry entry = new SearchTreeEntry(new GUIContent(listItems[i]))
|
SearchTreeEntry entry = new SearchTreeEntry(new GUIContent(listItems[i]))
|
||||||
{
|
{
|
||||||
|
@ -237,18 +271,15 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection.Editor
|
||||||
};
|
};
|
||||||
searchList.Add(entry);
|
searchList.Add(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
return searchList;
|
return searchList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnSelectEntry(SearchTreeEntry SearchTreeEntry, SearchWindowContext context)
|
public bool OnSelectEntry(SearchTreeEntry SearchTreeEntry, SearchWindowContext context)
|
||||||
{
|
{
|
||||||
onSetIndexCallback?.Invoke((int)SearchTreeEntry.userData);
|
onSetIndexCallback?.Invoke((int)SearchTreeEntry.userData);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Sentry;
|
using Sentry;
|
||||||
using Speckle.ConnectorUnity.Components;
|
using Speckle.ConnectorUnity.Components;
|
||||||
using Speckle.ConnectorUnity.Utils;
|
using Speckle.ConnectorUnity.Utils;
|
||||||
|
@ -17,184 +16,201 @@ using UnityEngine;
|
||||||
|
|
||||||
namespace Speckle.ConnectorUnity
|
namespace Speckle.ConnectorUnity
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// A Speckle Receiver, it's a wrapper around a basic Speckle Client
|
|
||||||
/// that handles conversions and subscriptions for you
|
|
||||||
/// </summary>
|
|
||||||
[RequireComponent(typeof(RecursiveConverter))]
|
|
||||||
[Obsolete]
|
|
||||||
public class Receiver : MonoBehaviour
|
|
||||||
{
|
|
||||||
public string StreamId;
|
|
||||||
public string BranchName = "main";
|
|
||||||
public Stream Stream;
|
|
||||||
public int TotalChildrenCount = 0;
|
|
||||||
public GameObject ReceivedData;
|
|
||||||
|
|
||||||
private bool AutoReceive;
|
|
||||||
private bool DeleteOld;
|
|
||||||
private Action<ConcurrentDictionary<string, int>> OnProgressAction;
|
|
||||||
private Action<string, Exception> OnErrorAction;
|
|
||||||
private Action<int> OnTotalChildrenCountKnown;
|
|
||||||
private Action<GameObject> OnDataReceivedAction;
|
|
||||||
|
|
||||||
|
|
||||||
private Client Client { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public Receiver()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes the Receiver manually
|
/// A Speckle Receiver, it's a wrapper around a basic Speckle Client
|
||||||
|
/// that handles conversions and subscriptions for you
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="streamId">Id of the stream to receive</param>
|
[RequireComponent(typeof(RecursiveConverter))]
|
||||||
/// <param name="autoReceive">If true, it will automatically receive updates sent to this stream</param>
|
[Obsolete]
|
||||||
/// <param name="deleteOld">If true, it will delete previously received objects when new one are received</param>
|
public class Receiver : MonoBehaviour
|
||||||
/// <param name="account">Account to use, if null the default account will be used</param>
|
|
||||||
/// <param name="onDataReceivedAction">Action to run after new data has been received and converted</param>
|
|
||||||
/// <param name="onProgressAction">Action to run when there is download/conversion progress</param>
|
|
||||||
/// <param name="onErrorAction">Action to run on error</param>
|
|
||||||
/// <param name="onTotalChildrenCountKnown">Action to run when the TotalChildrenCount is known</param>
|
|
||||||
public void Init(string streamId, bool autoReceive = false, bool deleteOld = true, Account account = null,
|
|
||||||
Action<GameObject> onDataReceivedAction = null, Action<ConcurrentDictionary<string, int>> onProgressAction = null,
|
|
||||||
Action<string, Exception> onErrorAction = null, Action<int> onTotalChildrenCountKnown = null)
|
|
||||||
{
|
{
|
||||||
StreamId = streamId;
|
public string StreamId;
|
||||||
AutoReceive = autoReceive;
|
public string BranchName = "main";
|
||||||
DeleteOld = deleteOld;
|
public Stream Stream;
|
||||||
OnDataReceivedAction = onDataReceivedAction;
|
public int TotalChildrenCount = 0;
|
||||||
OnErrorAction = onErrorAction;
|
public GameObject ReceivedData;
|
||||||
OnProgressAction = onProgressAction;
|
|
||||||
OnTotalChildrenCountKnown = onTotalChildrenCountKnown;
|
|
||||||
|
|
||||||
Client = new Client(account ?? AccountManager.GetDefaultAccount());
|
private bool AutoReceive;
|
||||||
|
private bool DeleteOld;
|
||||||
|
private Action<ConcurrentDictionary<string, int>> OnProgressAction;
|
||||||
|
private Action<string, Exception> OnErrorAction;
|
||||||
|
private Action<int> OnTotalChildrenCountKnown;
|
||||||
|
private Action<GameObject> OnDataReceivedAction;
|
||||||
|
|
||||||
|
private Client Client { get; set; }
|
||||||
|
|
||||||
if (AutoReceive)
|
public Receiver() { }
|
||||||
{
|
|
||||||
Client.SubscribeCommitCreated(StreamId);
|
|
||||||
Client.OnCommitCreated += Client_OnCommitCreated;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Initializes the Receiver manually
|
||||||
/// Gets and converts the data of the last commit on the Stream
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="streamId">Id of the stream to receive</param>
|
||||||
/// <returns></returns>
|
/// <param name="autoReceive">If true, it will automatically receive updates sent to this stream</param>
|
||||||
public void Receive()
|
/// <param name="deleteOld">If true, it will delete previously received objects when new one are received</param>
|
||||||
{
|
/// <param name="account">Account to use, if null the default account will be used</param>
|
||||||
if (Client == null || string.IsNullOrEmpty(StreamId))
|
/// <param name="onDataReceivedAction">Action to run after new data has been received and converted</param>
|
||||||
throw new Exception("Receiver has not been initialized. Please call Init().");
|
/// <param name="onProgressAction">Action to run when there is download/conversion progress</param>
|
||||||
|
/// <param name="onErrorAction">Action to run on error</param>
|
||||||
Task.Run(async () =>
|
/// <param name="onTotalChildrenCountKnown">Action to run when the TotalChildrenCount is known</param>
|
||||||
{
|
public void Init(
|
||||||
try
|
string streamId,
|
||||||
|
bool autoReceive = false,
|
||||||
|
bool deleteOld = true,
|
||||||
|
Account account = null,
|
||||||
|
Action<GameObject> onDataReceivedAction = null,
|
||||||
|
Action<ConcurrentDictionary<string, int>> onProgressAction = null,
|
||||||
|
Action<string, Exception> onErrorAction = null,
|
||||||
|
Action<int> onTotalChildrenCountKnown = null
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var mainBranch = await Client.BranchGet(StreamId, BranchName, 1);
|
StreamId = streamId;
|
||||||
if (!mainBranch.commits.items.Any())
|
AutoReceive = autoReceive;
|
||||||
throw new Exception("This branch has no commits");
|
DeleteOld = deleteOld;
|
||||||
var commit = mainBranch.commits.items[0];
|
OnDataReceivedAction = onDataReceivedAction;
|
||||||
GetAndConvertObject(commit.referencedObject, commit.id, commit.sourceApplication, commit.authorId);
|
OnErrorAction = onErrorAction;
|
||||||
|
OnProgressAction = onProgressAction;
|
||||||
|
OnTotalChildrenCountKnown = onTotalChildrenCountKnown;
|
||||||
|
|
||||||
|
Client = new Client(account ?? AccountManager.GetDefaultAccount());
|
||||||
|
|
||||||
|
if (AutoReceive)
|
||||||
|
{
|
||||||
|
Client.SubscribeCommitCreated(StreamId);
|
||||||
|
Client.OnCommitCreated += Client_OnCommitCreated;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets and converts the data of the last commit on the Stream
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public void Receive()
|
||||||
{
|
{
|
||||||
throw new SpeckleException(e.Message, e, true, SentryLevel.Error);
|
if (Client == null || string.IsNullOrEmpty(StreamId))
|
||||||
|
throw new Exception("Receiver has not been initialized. Please call Init().");
|
||||||
|
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var mainBranch = await Client.BranchGet(StreamId, BranchName, 1);
|
||||||
|
if (!mainBranch.commits.items.Any())
|
||||||
|
throw new Exception("This branch has no commits");
|
||||||
|
var commit = mainBranch.commits.items[0];
|
||||||
|
GetAndConvertObject(
|
||||||
|
commit.referencedObject,
|
||||||
|
commit.id,
|
||||||
|
commit.sourceApplication,
|
||||||
|
commit.authorId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new SpeckleException(e.Message, e, true, SentryLevel.Error);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#region private methods
|
||||||
|
|
||||||
#region private methods
|
/// <summary>
|
||||||
|
/// Fired when a new commit is created on this stream
|
||||||
/// <summary>
|
/// It receives and converts the objects and then executes the user defined _onCommitCreated action.
|
||||||
/// Fired when a new commit is created on this stream
|
/// </summary>
|
||||||
/// It receives and converts the objects and then executes the user defined _onCommitCreated action.
|
/// <param name="sender"></param>
|
||||||
/// </summary>
|
/// <param name="e"></param>
|
||||||
/// <param name="sender"></param>
|
protected virtual void Client_OnCommitCreated(object sender, CommitInfo e)
|
||||||
/// <param name="e"></param>
|
|
||||||
protected virtual void Client_OnCommitCreated(object sender, CommitInfo e)
|
|
||||||
{
|
|
||||||
if (e.branchName == BranchName)
|
|
||||||
{
|
|
||||||
Debug.Log("New commit created");
|
|
||||||
GetAndConvertObject(e.objectId, e.id, e.sourceApplication, e.authorId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private async void GetAndConvertObject(string objectId, string commitId, string sourceApplication, string authorId)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
var transport = new ServerTransport(Client.Account, StreamId);
|
|
||||||
var @base = await Operations.Receive(
|
|
||||||
objectId,
|
|
||||||
remoteTransport: transport,
|
|
||||||
onErrorAction: OnErrorAction,
|
|
||||||
onProgressAction: OnProgressAction,
|
|
||||||
onTotalChildrenCountKnown: OnTotalChildrenCountKnown,
|
|
||||||
disposeTransports: true
|
|
||||||
);
|
|
||||||
|
|
||||||
Analytics.TrackEvent(Client.Account, Analytics.Events.Receive, new Dictionary<string, object>()
|
|
||||||
{
|
{
|
||||||
{"mode", nameof(Receiver)},
|
if (e.branchName == BranchName)
|
||||||
{"sourceHostApp", HostApplications.GetHostAppFromString(sourceApplication).Slug},
|
{
|
||||||
{"sourceHostAppVersion", sourceApplication ?? ""},
|
Debug.Log("New commit created");
|
||||||
{"hostPlatform", Application.platform.ToString()},
|
GetAndConvertObject(e.objectId, e.id, e.sourceApplication, e.authorId);
|
||||||
{"isMultiplayer", authorId != null && authorId != Client.Account.userInfo.id},
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
Dispatcher.Instance().Enqueue(() =>
|
private async void GetAndConvertObject(
|
||||||
|
string objectId,
|
||||||
|
string commitId,
|
||||||
|
string sourceApplication,
|
||||||
|
string authorId
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var root = new GameObject()
|
try
|
||||||
{
|
{
|
||||||
name = commitId,
|
var transport = new ServerTransport(Client.Account, StreamId);
|
||||||
};
|
var @base = await Operations.Receive(
|
||||||
|
objectId,
|
||||||
|
remoteTransport: transport,
|
||||||
|
onErrorAction: OnErrorAction,
|
||||||
|
onProgressAction: OnProgressAction,
|
||||||
|
onTotalChildrenCountKnown: OnTotalChildrenCountKnown,
|
||||||
|
disposeTransports: true
|
||||||
|
);
|
||||||
|
|
||||||
var rc = GetComponent<RecursiveConverter>();
|
Analytics.TrackEvent(
|
||||||
var go = rc.RecursivelyConvertToNative(@base, root.transform);
|
Client.Account,
|
||||||
//remove previously received object
|
Analytics.Events.Receive,
|
||||||
if (DeleteOld && ReceivedData != null)
|
new Dictionary<string, object>()
|
||||||
Destroy(ReceivedData);
|
{
|
||||||
ReceivedData = root;
|
{ "mode", nameof(Receiver) },
|
||||||
OnDataReceivedAction?.Invoke(root);
|
{
|
||||||
});
|
"sourceHostApp",
|
||||||
}
|
HostApplications.GetHostAppFromString(sourceApplication).Slug
|
||||||
catch (Exception e)
|
},
|
||||||
{
|
{ "sourceHostAppVersion", sourceApplication ?? "" },
|
||||||
throw new SpeckleException(e.Message, e, true, SentryLevel.Error);
|
{ "hostPlatform", Application.platform.ToString() },
|
||||||
}
|
{
|
||||||
|
"isMultiplayer",
|
||||||
try
|
authorId != null && authorId != Client.Account.userInfo.id
|
||||||
{
|
},
|
||||||
await Client.CommitReceived(new CommitReceivedInput
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Dispatcher
|
||||||
|
.Instance()
|
||||||
|
.Enqueue(() =>
|
||||||
|
{
|
||||||
|
var root = new GameObject() { name = commitId, };
|
||||||
|
|
||||||
|
var rc = GetComponent<RecursiveConverter>();
|
||||||
|
var go = rc.RecursivelyConvertToNative(@base, root.transform);
|
||||||
|
//remove previously received object
|
||||||
|
if (DeleteOld && ReceivedData != null)
|
||||||
|
Destroy(ReceivedData);
|
||||||
|
ReceivedData = root;
|
||||||
|
OnDataReceivedAction?.Invoke(root);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new SpeckleException(e.Message, e, true, SentryLevel.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Client.CommitReceived(
|
||||||
|
new CommitReceivedInput
|
||||||
|
{
|
||||||
|
streamId = StreamId,
|
||||||
|
commitId = commitId,
|
||||||
|
message = $"received commit from {Application.unityVersion}",
|
||||||
|
sourceApplication = HostApplications.Unity.GetVersion(
|
||||||
|
CoreUtils.GetHostAppVersion()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Do nothing!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
{
|
{
|
||||||
streamId = StreamId,
|
Client?.CommitCreatedSubscription?.Dispose();
|
||||||
commitId = commitId,
|
}
|
||||||
message = $"received commit from {Application.unityVersion}",
|
|
||||||
sourceApplication = HostApplications.Unity.GetVersion(CoreUtils.GetHostAppVersion())
|
#endregion
|
||||||
});
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Do nothing!
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
Client?.CommitCreatedSubscription?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,135 +16,150 @@ using UnityEngine.SceneManagement;
|
||||||
|
|
||||||
namespace Speckle.ConnectorUnity
|
namespace Speckle.ConnectorUnity
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// A Speckle Sender, it's a wrapper around a basic Speckle Client
|
|
||||||
/// that handles conversions for you
|
|
||||||
/// </summary>
|
|
||||||
[RequireComponent(typeof(RecursiveConverter)), ExecuteAlways]
|
|
||||||
[Obsolete]
|
|
||||||
public class Sender : MonoBehaviour
|
|
||||||
{
|
|
||||||
|
|
||||||
private ServerTransport transport;
|
|
||||||
private RecursiveConverter converter;
|
|
||||||
private CancellationTokenSource cancellationTokenSource;
|
|
||||||
|
|
||||||
#nullable enable
|
|
||||||
|
|
||||||
private void Awake()
|
|
||||||
{
|
|
||||||
converter = GetComponent<RecursiveConverter>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts and sends the data of the last commit on the Stream
|
/// A Speckle Sender, it's a wrapper around a basic Speckle Client
|
||||||
|
/// that handles conversions for you
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="streamId">ID of the stream to send to</param>
|
[RequireComponent(typeof(RecursiveConverter)), ExecuteAlways]
|
||||||
/// <param name="gameObjects">List of gameObjects to convert and send</param>
|
[Obsolete]
|
||||||
/// <param name="account">Account to use. If not provided the default account will be used</param>
|
public class Sender : MonoBehaviour
|
||||||
/// <param name="branchName">Name of branch to send to</param>
|
|
||||||
/// <param name="createCommit">When true, will create a commit using the root object</param>
|
|
||||||
/// <param name="onDataSentAction">Action to run after the data has been sent</param>
|
|
||||||
/// <param name="onProgressAction">Action to run when there is download/conversion progress</param>
|
|
||||||
/// <param name="onErrorAction">Action to run on error</param>
|
|
||||||
/// <exception cref="SpeckleException"></exception>
|
|
||||||
public void Send(string streamId,
|
|
||||||
ISet<GameObject> gameObjects,
|
|
||||||
Account? account = null,
|
|
||||||
string branchName = "main",
|
|
||||||
bool createCommit = true,
|
|
||||||
Action<string>? onDataSentAction = null,
|
|
||||||
Action<ConcurrentDictionary<string, int>>? onProgressAction = null,
|
|
||||||
Action<string, Exception>? onErrorAction = null)
|
|
||||||
{
|
{
|
||||||
try
|
private ServerTransport transport;
|
||||||
{
|
private RecursiveConverter converter;
|
||||||
CancelOperations();
|
private CancellationTokenSource cancellationTokenSource;
|
||||||
|
|
||||||
cancellationTokenSource = new CancellationTokenSource();
|
|
||||||
|
|
||||||
var client = new Client(account ?? AccountManager.GetDefaultAccount());
|
|
||||||
transport = new ServerTransport(client.Account, streamId);
|
|
||||||
transport.CancellationToken = cancellationTokenSource.Token;
|
|
||||||
|
|
||||||
var rootObjects = SceneManager.GetActiveScene().GetRootGameObjects();
|
|
||||||
|
|
||||||
var data = converter.RecursivelyConvertToSpeckle(rootObjects,
|
|
||||||
o => gameObjects.Contains(o));
|
|
||||||
|
|
||||||
SendData(transport, data, client, branchName, createCommit, cancellationTokenSource.Token, onDataSentAction, onProgressAction, onErrorAction);
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new SpeckleException(e.ToString(), e, true, SentryLevel.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public static void SendData(ServerTransport remoteTransport,
|
private void Awake()
|
||||||
Base data,
|
|
||||||
Client client,
|
|
||||||
string branchName,
|
|
||||||
bool createCommit,
|
|
||||||
CancellationToken cancellationToken,
|
|
||||||
Action<string>? onDataSentAction = null,
|
|
||||||
Action<ConcurrentDictionary<string, int>>? onProgressAction = null,
|
|
||||||
Action<string, Exception>? onErrorAction = null)
|
|
||||||
{
|
|
||||||
|
|
||||||
Task.Run(async () =>
|
|
||||||
{
|
|
||||||
|
|
||||||
var res = await Operations.Send(
|
|
||||||
data,
|
|
||||||
cancellationToken: cancellationToken,
|
|
||||||
new List<ITransport>() {remoteTransport},
|
|
||||||
useDefaultCache: true,
|
|
||||||
disposeTransports: true,
|
|
||||||
onProgressAction: onProgressAction,
|
|
||||||
onErrorAction: onErrorAction
|
|
||||||
);
|
|
||||||
|
|
||||||
Analytics.TrackEvent(client.Account, Analytics.Events.Send);
|
|
||||||
|
|
||||||
if (createCommit && !cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
{
|
||||||
long count = data.GetTotalChildrenCount();
|
converter = GetComponent<RecursiveConverter>();
|
||||||
|
|
||||||
await client.CommitCreate(cancellationToken,
|
|
||||||
new CommitCreateInput
|
|
||||||
{
|
|
||||||
streamId = remoteTransport.StreamId,
|
|
||||||
branchName = branchName,
|
|
||||||
objectId = res,
|
|
||||||
message = $"Sent {count} objects from Unity",
|
|
||||||
sourceApplication = HostApplications.Unity.Name,
|
|
||||||
totalChildrenCount = (int)count,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onDataSentAction?.Invoke(res);
|
/// <summary>
|
||||||
}, cancellationToken);
|
/// Converts and sends the data of the last commit on the Stream
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="streamId">ID of the stream to send to</param>
|
||||||
|
/// <param name="gameObjects">List of gameObjects to convert and send</param>
|
||||||
|
/// <param name="account">Account to use. If not provided the default account will be used</param>
|
||||||
|
/// <param name="branchName">Name of branch to send to</param>
|
||||||
|
/// <param name="createCommit">When true, will create a commit using the root object</param>
|
||||||
|
/// <param name="onDataSentAction">Action to run after the data has been sent</param>
|
||||||
|
/// <param name="onProgressAction">Action to run when there is download/conversion progress</param>
|
||||||
|
/// <param name="onErrorAction">Action to run on error</param>
|
||||||
|
/// <exception cref="SpeckleException"></exception>
|
||||||
|
public void Send(
|
||||||
|
string streamId,
|
||||||
|
ISet<GameObject> gameObjects,
|
||||||
|
Account? account = null,
|
||||||
|
string branchName = "main",
|
||||||
|
bool createCommit = true,
|
||||||
|
Action<string>? onDataSentAction = null,
|
||||||
|
Action<ConcurrentDictionary<string, int>>? onProgressAction = null,
|
||||||
|
Action<string, Exception>? onErrorAction = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CancelOperations();
|
||||||
|
|
||||||
|
cancellationTokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
|
var client = new Client(account ?? AccountManager.GetDefaultAccount());
|
||||||
|
transport = new ServerTransport(client.Account, streamId);
|
||||||
|
transport.CancellationToken = cancellationTokenSource.Token;
|
||||||
|
|
||||||
|
var rootObjects = SceneManager.GetActiveScene().GetRootGameObjects();
|
||||||
|
|
||||||
|
var data = converter.RecursivelyConvertToSpeckle(
|
||||||
|
rootObjects,
|
||||||
|
o => gameObjects.Contains(o)
|
||||||
|
);
|
||||||
|
|
||||||
|
SendData(
|
||||||
|
transport,
|
||||||
|
data,
|
||||||
|
client,
|
||||||
|
branchName,
|
||||||
|
createCommit,
|
||||||
|
cancellationTokenSource.Token,
|
||||||
|
onDataSentAction,
|
||||||
|
onProgressAction,
|
||||||
|
onErrorAction
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new SpeckleException(e.ToString(), e, true, SentryLevel.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendData(
|
||||||
|
ServerTransport remoteTransport,
|
||||||
|
Base data,
|
||||||
|
Client client,
|
||||||
|
string branchName,
|
||||||
|
bool createCommit,
|
||||||
|
CancellationToken cancellationToken,
|
||||||
|
Action<string>? onDataSentAction = null,
|
||||||
|
Action<ConcurrentDictionary<string, int>>? onProgressAction = null,
|
||||||
|
Action<string, Exception>? onErrorAction = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Task.Run(
|
||||||
|
async () =>
|
||||||
|
{
|
||||||
|
var res = await Operations.Send(
|
||||||
|
data,
|
||||||
|
cancellationToken: cancellationToken,
|
||||||
|
new List<ITransport>() { remoteTransport },
|
||||||
|
useDefaultCache: true,
|
||||||
|
disposeTransports: true,
|
||||||
|
onProgressAction: onProgressAction,
|
||||||
|
onErrorAction: onErrorAction
|
||||||
|
);
|
||||||
|
|
||||||
|
Analytics.TrackEvent(client.Account, Analytics.Events.Send);
|
||||||
|
|
||||||
|
if (createCommit && !cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
long count = data.GetTotalChildrenCount();
|
||||||
|
|
||||||
|
await client.CommitCreate(
|
||||||
|
cancellationToken,
|
||||||
|
new CommitCreateInput
|
||||||
|
{
|
||||||
|
streamId = remoteTransport.StreamId,
|
||||||
|
branchName = branchName,
|
||||||
|
objectId = res,
|
||||||
|
message = $"Sent {count} objects from Unity",
|
||||||
|
sourceApplication = HostApplications.Unity.Name,
|
||||||
|
totalChildrenCount = (int)count,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDataSentAction?.Invoke(res);
|
||||||
|
},
|
||||||
|
cancellationToken
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
CancelOperations();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CancelOperations()
|
||||||
|
{
|
||||||
|
cancellationTokenSource?.Cancel();
|
||||||
|
transport?.Dispose();
|
||||||
|
cancellationTokenSource?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region private methods
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
CancelOperations();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CancelOperations()
|
|
||||||
{
|
|
||||||
cancellationTokenSource?.Cancel();
|
|
||||||
transport?.Dispose();
|
|
||||||
cancellationTokenSource?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#region private methods
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,16 +29,18 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
public List<Branch> Branches;
|
public List<Branch> Branches;
|
||||||
|
|
||||||
public RecursiveConverter RC { get; private set; }
|
public RecursiveConverter RC { get; private set; }
|
||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
RC = GetComponent<RecursiveConverter>();
|
RC = GetComponent<RecursiveConverter>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GameObject ConvertRecursivelyToNative(
|
||||||
public GameObject ConvertRecursivelyToNative(Base @base, string rootObjectName,
|
Base @base,
|
||||||
Action<Base>? beforeConvertCallback)
|
string rootObjectName,
|
||||||
|
Action<Base>? beforeConvertCallback
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var rootObject = new GameObject(rootObjectName);
|
var rootObject = new GameObject(rootObjectName);
|
||||||
|
|
||||||
|
@ -46,10 +48,9 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
{
|
{
|
||||||
beforeConvertCallback?.Invoke(o);
|
beforeConvertCallback?.Invoke(o);
|
||||||
return RC.ConverterInstance.CanConvertToNative(o) //Accept geometry
|
return RC.ConverterInstance.CanConvertToNative(o) //Accept geometry
|
||||||
|| o.speckle_type == nameof(Base) && o.totalChildrenCount > 0; // Or Base objects that have children
|
|| o.speckle_type == nameof(Base) && o.totalChildrenCount > 0; // Or Base objects that have children
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// For the rootObject only, we will create property GameObjects
|
// For the rootObject only, we will create property GameObjects
|
||||||
// i.e. revit categories
|
// i.e. revit categories
|
||||||
foreach (var prop in @base.GetMembers())
|
foreach (var prop in @base.GetMembers())
|
||||||
|
@ -57,13 +58,15 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
var converted = RC.RecursivelyConvertToNative(prop.Value, null, Predicate);
|
var converted = RC.RecursivelyConvertToNative(prop.Value, null, Predicate);
|
||||||
|
|
||||||
//Skip empties
|
//Skip empties
|
||||||
if (converted.Count <= 0) continue;
|
if (converted.Count <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
var propertyObject = new GameObject(prop.Key);
|
var propertyObject = new GameObject(prop.Key);
|
||||||
propertyObject.transform.SetParent(rootObject.transform);
|
propertyObject.transform.SetParent(rootObject.transform);
|
||||||
foreach (var o in converted)
|
foreach (var o in converted)
|
||||||
{
|
{
|
||||||
if (o.transform.parent == null) o.transform.SetParent(propertyObject.transform);
|
if (o.transform.parent == null)
|
||||||
|
o.transform.SetParent(propertyObject.transform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,4 +83,4 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,12 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
{
|
{
|
||||||
[Tooltip("Url of your speckle object/commit/branch/stream")]
|
[Tooltip("Url of your speckle object/commit/branch/stream")]
|
||||||
public string url;
|
public string url;
|
||||||
|
|
||||||
private RecursiveConverter _converter;
|
private RecursiveConverter _converter;
|
||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
private CancellationTokenSource? _tokenSource;
|
private CancellationTokenSource? _tokenSource;
|
||||||
|
|
||||||
void Awake()
|
void Awake()
|
||||||
{
|
{
|
||||||
_converter = GetComponent<RecursiveConverter>();
|
_converter = GetComponent<RecursiveConverter>();
|
||||||
|
@ -32,38 +33,49 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
{
|
{
|
||||||
StartCoroutine(Receive_Routine());
|
StartCoroutine(Receive_Routine());
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator Receive_Routine()
|
public IEnumerator Receive_Routine()
|
||||||
{
|
{
|
||||||
if (IsBusy()) throw new InvalidOperationException("A receive operation has already started");
|
if (IsBusy())
|
||||||
|
throw new InvalidOperationException("A receive operation has already started");
|
||||||
_tokenSource = new CancellationTokenSource();
|
_tokenSource = new CancellationTokenSource();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
StreamWrapper sw = new(url);
|
StreamWrapper sw = new(url);
|
||||||
|
|
||||||
if (!sw.IsValid)
|
if (!sw.IsValid)
|
||||||
throw new InvalidOperationException("Speckle url input is not a valid speckle stream/branch/commit");
|
throw new InvalidOperationException(
|
||||||
|
"Speckle url input is not a valid speckle stream/branch/commit"
|
||||||
|
);
|
||||||
|
|
||||||
var accountTask = new Utils.Utils.WaitForTask<Account>(async () => await GetAccount(sw));
|
var accountTask = new Utils.Utils.WaitForTask<Account>(
|
||||||
|
async () => await GetAccount(sw)
|
||||||
|
);
|
||||||
yield return accountTask;
|
yield return accountTask;
|
||||||
|
|
||||||
_tokenSource.Token.ThrowIfCancellationRequested();
|
_tokenSource.Token.ThrowIfCancellationRequested();
|
||||||
using Client c = new(accountTask.Result);
|
using Client c = new(accountTask.Result);
|
||||||
|
|
||||||
var objectIdTask = new Utils.Utils.WaitForTask<(string, Commit?)>(async () => await GetObjectID(sw, c));
|
var objectIdTask = new Utils.Utils.WaitForTask<(string, Commit?)>(
|
||||||
|
async () => await GetObjectID(sw, c)
|
||||||
|
);
|
||||||
yield return objectIdTask;
|
yield return objectIdTask;
|
||||||
(string objectId, Commit? commit) = objectIdTask.Result;
|
(string objectId, Commit? commit) = objectIdTask.Result;
|
||||||
|
|
||||||
Debug.Log($"Receiving from {sw.ServerUrl}...");
|
Debug.Log($"Receiving from {sw.ServerUrl}...");
|
||||||
|
|
||||||
var receiveTask = new Utils.Utils.WaitForTask<Base>(async () => await SpeckleReceiver.ReceiveAsync(
|
var receiveTask = new Utils.Utils.WaitForTask<Base>(
|
||||||
c,
|
async () =>
|
||||||
sw.StreamId,
|
await SpeckleReceiver.ReceiveAsync(
|
||||||
objectId,
|
c,
|
||||||
commit,
|
sw.StreamId,
|
||||||
cancellationToken: _tokenSource.Token));
|
objectId,
|
||||||
|
commit,
|
||||||
|
cancellationToken: _tokenSource.Token
|
||||||
|
)
|
||||||
|
);
|
||||||
yield return receiveTask;
|
yield return receiveTask;
|
||||||
|
|
||||||
Debug.Log("Converting to native...");
|
Debug.Log("Converting to native...");
|
||||||
_converter.RecursivelyConvertToNative_Sync(receiveTask.Result, transform);
|
_converter.RecursivelyConvertToNative_Sync(receiveTask.Result, transform);
|
||||||
}
|
}
|
||||||
|
@ -74,8 +86,10 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<(string objectId, Commit? commit)> GetObjectID(
|
||||||
private async Task<(string objectId, Commit? commit)> GetObjectID(StreamWrapper sw, Client client)
|
StreamWrapper sw,
|
||||||
|
Client client
|
||||||
|
)
|
||||||
{
|
{
|
||||||
string objectId;
|
string objectId;
|
||||||
Commit? commit = null;
|
Commit? commit = null;
|
||||||
|
@ -95,7 +109,9 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
{
|
{
|
||||||
var branchName = string.IsNullOrEmpty(sw.BranchName) ? "main" : sw.BranchName;
|
var branchName = string.IsNullOrEmpty(sw.BranchName) ? "main" : sw.BranchName;
|
||||||
|
|
||||||
var branch = await client.BranchGet(sw.StreamId, branchName, 1).ConfigureAwait(false);
|
var branch = await client
|
||||||
|
.BranchGet(sw.StreamId, branchName, 1)
|
||||||
|
.ConfigureAwait(false);
|
||||||
if (!branch.commits.items.Any())
|
if (!branch.commits.items.Any())
|
||||||
throw new SpeckleException("The selected branch has no commits.");
|
throw new SpeckleException("The selected branch has no commits.");
|
||||||
|
|
||||||
|
@ -105,19 +121,23 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
|
|
||||||
return (objectId, commit);
|
return (objectId, commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
[ContextMenu(nameof(Cancel))]
|
[ContextMenu(nameof(Cancel))]
|
||||||
public void Cancel()
|
public void Cancel()
|
||||||
{
|
{
|
||||||
if (IsNotBusy()) throw new InvalidOperationException("There are no pending receive operations to cancel");
|
if (IsNotBusy())
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"There are no pending receive operations to cancel"
|
||||||
|
);
|
||||||
_tokenSource!.Cancel();
|
_tokenSource!.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
[ContextMenu(nameof(Cancel), true)]
|
[ContextMenu(nameof(Cancel), true)]
|
||||||
public bool IsBusy()
|
public bool IsBusy()
|
||||||
{
|
{
|
||||||
return _tokenSource is not null;
|
return _tokenSource is not null;
|
||||||
}
|
}
|
||||||
|
|
||||||
[ContextMenu(nameof(Receive), true)]
|
[ContextMenu(nameof(Receive), true)]
|
||||||
internal bool IsNotBusy() => !IsBusy();
|
internal bool IsNotBusy() => !IsBusy();
|
||||||
|
|
||||||
|
@ -126,7 +146,6 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
_tokenSource?.Cancel();
|
_tokenSource?.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private async Task<Account> GetAccount(StreamWrapper sw)
|
private async Task<Account> GetAccount(StreamWrapper sw)
|
||||||
{
|
{
|
||||||
Account account;
|
Account account;
|
||||||
|
@ -134,10 +153,10 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
{
|
{
|
||||||
account = await sw.GetAccount().ConfigureAwait(false);
|
account = await sw.GetAccount().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (SpeckleException e)
|
catch (SpeckleException)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(sw.StreamId))
|
if (string.IsNullOrEmpty(sw.StreamId))
|
||||||
throw e;
|
throw;
|
||||||
|
|
||||||
//Fallback to a non authed account
|
//Fallback to a non authed account
|
||||||
account = new Account
|
account = new Account
|
||||||
|
|
|
@ -12,7 +12,6 @@ using UnityEngine;
|
||||||
|
|
||||||
namespace Speckle.ConnectorUnity.Components
|
namespace Speckle.ConnectorUnity.Components
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Struct that encapsulates the result of a <see cref="RecursiveConverter"/> ToNative conversion of a single Speckle Object (<see cref="Base"/>)
|
/// Struct that encapsulates the result of a <see cref="RecursiveConverter"/> ToNative conversion of a single Speckle Object (<see cref="Base"/>)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -22,12 +21,12 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
/// The context that was converted ToNative
|
/// The context that was converted ToNative
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly TraversalContext traversalContext;
|
public readonly TraversalContext traversalContext;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The result of conversion a successful conversion
|
/// The result of conversion a successful conversion
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly GameObject? converted;
|
public readonly GameObject? converted;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The result of conversion a failed conversion
|
/// The result of conversion a failed conversion
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -42,7 +41,8 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
public ConversionResult(TraversalContext traversalContext, [NotNull] GameObject? converted)
|
public ConversionResult(TraversalContext traversalContext, [NotNull] GameObject? converted)
|
||||||
: this(traversalContext, converted, null)
|
: this(traversalContext, converted, null)
|
||||||
{
|
{
|
||||||
if (converted is null) throw new ArgumentNullException(nameof(converted));
|
if (converted is null)
|
||||||
|
throw new ArgumentNullException(nameof(converted));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -52,14 +52,22 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
/// <param name="exception">The operation halting exception that occured</param>
|
/// <param name="exception">The operation halting exception that occured</param>
|
||||||
/// <param name="converted">Optional converted GameObject</param>
|
/// <param name="converted">Optional converted GameObject</param>
|
||||||
/// <exception cref="ArgumentNullException"/>
|
/// <exception cref="ArgumentNullException"/>
|
||||||
public ConversionResult(TraversalContext traversalContext, [NotNull] Exception? exception,
|
public ConversionResult(
|
||||||
GameObject? converted = null)
|
TraversalContext traversalContext,
|
||||||
|
[NotNull] Exception? exception,
|
||||||
|
GameObject? converted = null
|
||||||
|
)
|
||||||
: this(traversalContext, converted, exception)
|
: this(traversalContext, converted, exception)
|
||||||
{
|
{
|
||||||
if (exception is null) throw new ArgumentNullException(nameof(exception));
|
if (exception is null)
|
||||||
|
throw new ArgumentNullException(nameof(exception));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConversionResult(TraversalContext traversalContext, GameObject? converted, Exception? exception)
|
private ConversionResult(
|
||||||
|
TraversalContext traversalContext,
|
||||||
|
GameObject? converted,
|
||||||
|
Exception? exception
|
||||||
|
)
|
||||||
{
|
{
|
||||||
this.traversalContext = traversalContext;
|
this.traversalContext = traversalContext;
|
||||||
this.converted = converted;
|
this.converted = converted;
|
||||||
|
@ -67,28 +75,28 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="converted">The converted <see cref="GameObject"/></param>
|
/// <param name="converted">The converted <see cref="GameObject"/></param>
|
||||||
/// <param name="exception">The <see cref="exception"/> that occured during conversion</param>
|
/// <param name="exception">The <see cref="exception"/> that occured during conversion</param>
|
||||||
/// <returns>True if the conversion was successful</returns>
|
/// <returns>True if the conversion was successful</returns>
|
||||||
public bool WasSuccessful(
|
public bool WasSuccessful(
|
||||||
[NotNullWhen(true)] out GameObject? converted,
|
[NotNullWhen(true)] out GameObject? converted,
|
||||||
[NotNullWhen(false)] out Exception? exception)
|
[NotNullWhen(false)] out Exception? exception
|
||||||
|
)
|
||||||
{
|
{
|
||||||
converted = this.converted;
|
converted = this.converted;
|
||||||
exception = this.exception;
|
exception = this.exception;
|
||||||
return WasSuccessful();
|
return WasSuccessful();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool WasSuccessful() => this.exception == null;
|
public bool WasSuccessful() => this.exception == null;
|
||||||
|
|
||||||
public Base SpeckleObject => traversalContext.current;
|
public Base SpeckleObject => traversalContext.current;
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class RecursiveConverter
|
public partial class RecursiveConverter
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <inheritdoc cref="RecursivelyConvertToNative_Enumerable"/>
|
/// <inheritdoc cref="RecursivelyConvertToNative_Enumerable"/>
|
||||||
/// <remarks>Calling this function will perform the conversion process synchronously</remarks>
|
/// <remarks>Calling this function will perform the conversion process synchronously</remarks>
|
||||||
/// <returns>The conversion result</returns>
|
/// <returns>The conversion result</returns>
|
||||||
|
@ -100,7 +108,7 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
{
|
{
|
||||||
return RecursivelyConvertToNative_Enumerable(rootObject, parent, predicate).ToList();
|
return RecursivelyConvertToNative_Enumerable(rootObject, parent, predicate).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="RecursivelyConvertToNative_Enumerable"/>
|
/// <inheritdoc cref="RecursivelyConvertToNative_Enumerable"/>
|
||||||
/// <remarks>Calling this function will start a coroutine to complete later on the coroutine loop</remarks>
|
/// <remarks>Calling this function will start a coroutine to complete later on the coroutine loop</remarks>
|
||||||
/// <returns>The started Coroutine</returns>
|
/// <returns>The started Coroutine</returns>
|
||||||
|
@ -110,12 +118,14 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
Predicate<TraversalContext>? predicate = null
|
Predicate<TraversalContext>? predicate = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return StartCoroutine(RecursivelyConvertToNative_Enumerable(rootObject, parent, predicate).GetEnumerator());
|
return StartCoroutine(
|
||||||
|
RecursivelyConvertToNative_Enumerable(rootObject, parent, predicate).GetEnumerator()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Will recursively traverse the given <paramref name="rootObject"/> and convert convertable child objects
|
/// Will recursively traverse the given <paramref name="rootObject"/> and convert convertable child objects
|
||||||
/// where the given <see cref="predicate"/>
|
/// where the given <see cref="predicate"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="rootObject">The Speckle object to traverse and convert all convertable children</param>
|
/// <param name="rootObject">The Speckle object to traverse and convert all convertable children</param>
|
||||||
/// <param name="parent">Optional parent <see cref="Transform"/> for the created root <see cref="GameObject"/>s</param>
|
/// <param name="parent">Optional parent <see cref="Transform"/> for the created root <see cref="GameObject"/>s</param>
|
||||||
|
@ -124,12 +134,13 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
public IEnumerable<ConversionResult> RecursivelyConvertToNative_Enumerable(
|
public IEnumerable<ConversionResult> RecursivelyConvertToNative_Enumerable(
|
||||||
Base rootObject,
|
Base rootObject,
|
||||||
Transform? parent,
|
Transform? parent,
|
||||||
Predicate<TraversalContext>? predicate = null)
|
Predicate<TraversalContext>? predicate = null
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var userPredicate = predicate ?? (_ => true);
|
var userPredicate = predicate ?? (_ => true);
|
||||||
|
|
||||||
var traversalFunc = DefaultTraversal.CreateBIMTraverseFunc(ConverterInstance);
|
var traversalFunc = DefaultTraversal.CreateBIMTraverseFunc(ConverterInstance);
|
||||||
|
|
||||||
var objectsToConvert = traversalFunc
|
var objectsToConvert = traversalFunc
|
||||||
.Traverse(rootObject)
|
.Traverse(rootObject)
|
||||||
.Where(x => ConverterInstance.CanConvertToNative(x.current))
|
.Where(x => ConverterInstance.CanConvertToNative(x.current))
|
||||||
|
@ -138,7 +149,10 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
Dictionary<Base, GameObject?> created = new();
|
Dictionary<Base, GameObject?> created = new();
|
||||||
foreach (var conversionResult in ConvertTree(objectsToConvert, parent, created))
|
foreach (var conversionResult in ConvertTree(objectsToConvert, parent, created))
|
||||||
{
|
{
|
||||||
if (!isActiveAndEnabled) throw new InvalidOperationException($"Cannot convert objects while {GetType()} is disabled");
|
if (!isActiveAndEnabled)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Cannot convert objects while {GetType()} is disabled"
|
||||||
|
);
|
||||||
|
|
||||||
yield return conversionResult;
|
yield return conversionResult;
|
||||||
}
|
}
|
||||||
|
@ -150,17 +164,21 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
/// or <see langword="null"/> if not.
|
/// or <see langword="null"/> if not.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// You may enumerate over multiple frames (e.g. coroutine) but you must ensure the output eventually gets fully enumerated (exactly once)
|
/// You may enumerate over multiple frames (e.g. coroutine) but you must ensure the output eventually gets fully enumerated (exactly once)
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="objectTree"></param>
|
/// <param name="objectTree"></param>
|
||||||
/// <param name="parent"></param>
|
/// <param name="parent"></param>
|
||||||
/// <param name="outCreatedObjects"></param>
|
/// <param name="outCreatedObjects"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected IEnumerable<ConversionResult> ConvertTree(IEnumerable<TraversalContext> objectTree, Transform? parent, IDictionary<Base, GameObject?> outCreatedObjects)
|
protected IEnumerable<ConversionResult> ConvertTree(
|
||||||
|
IEnumerable<TraversalContext> objectTree,
|
||||||
|
Transform? parent,
|
||||||
|
IDictionary<Base, GameObject?> outCreatedObjects
|
||||||
|
)
|
||||||
{
|
{
|
||||||
InitializeAssetCache();
|
InitializeAssetCache();
|
||||||
AssetCache.BeginWrite();
|
AssetCache.BeginWrite();
|
||||||
|
|
||||||
foreach (TraversalContext tc in objectTree)
|
foreach (TraversalContext tc in objectTree)
|
||||||
{
|
{
|
||||||
ConversionResult result;
|
ConversionResult result;
|
||||||
|
@ -179,49 +197,69 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
|
|
||||||
yield return result;
|
yield return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetCache.FinishWrite();
|
AssetCache.FinishWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Transform? GetParent(TraversalContext? tc, IDictionary<Base, GameObject?> createdObjects)
|
protected static Transform? GetParent(
|
||||||
|
TraversalContext? tc,
|
||||||
|
IDictionary<Base, GameObject?> createdObjects
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (tc == null) return null; //We've reached the root object, and still not found a converted parent
|
if (tc == null)
|
||||||
|
return null; //We've reached the root object, and still not found a converted parent
|
||||||
if(createdObjects.TryGetValue(tc.current, out GameObject? p) && p != null)
|
|
||||||
|
if (createdObjects.TryGetValue(tc.current, out GameObject? p) && p != null)
|
||||||
return p.transform;
|
return p.transform;
|
||||||
|
|
||||||
//Go one level up, and repeat!
|
//Go one level up, and repeat!
|
||||||
return GetParent(tc.parent, createdObjects);
|
return GetParent(tc.parent, createdObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected GameObject ConvertToNative(Base speckleObject, Transform? parentTransform)
|
protected GameObject ConvertToNative(Base speckleObject, Transform? parentTransform)
|
||||||
{
|
{
|
||||||
GameObject? go = ConverterInstance.ConvertToNative(speckleObject) as GameObject;
|
GameObject? go = ConverterInstance.ConvertToNative(speckleObject) as GameObject;
|
||||||
if (go == null) throw new SpeckleException("Conversion Returned Null");
|
if (go == null)
|
||||||
|
throw new SpeckleException("Conversion Returned Null");
|
||||||
|
|
||||||
go.transform.SetParent(parentTransform, true);
|
go.transform.SetParent(parentTransform, true);
|
||||||
|
|
||||||
//Set some common for all created GameObjects
|
//Set some common for all created GameObjects
|
||||||
//TODO add support for more unity specific props
|
//TODO add support for more unity specific props
|
||||||
if(go.name == "New Game Object" || string.IsNullOrWhiteSpace(go.name))
|
if (go.name == "New Game Object" || string.IsNullOrWhiteSpace(go.name))
|
||||||
go.name = CoreUtils.GenerateObjectName(speckleObject);
|
go.name = CoreUtils.GenerateObjectName(speckleObject);
|
||||||
if (speckleObject["physicsLayer"] is string layerName)
|
if (speckleObject["physicsLayer"] is string layerName)
|
||||||
{
|
{
|
||||||
int layer = LayerMask.NameToLayer(layerName); //TODO: check how this can be interoperable with Unreal and Blender
|
int layer = LayerMask.NameToLayer(layerName); //TODO: check how this can be interoperable with Unreal and Blender
|
||||||
if (layer > -1) go.layer = layer;
|
if (layer > -1)
|
||||||
|
go.layer = layer;
|
||||||
}
|
}
|
||||||
//if (baseObject["tag"] is string t) go.tag = t;
|
//if (baseObject["tag"] is string t) go.tag = t;
|
||||||
//if (baseObject["isStatic"] is bool isStatic) go.isStatic = isStatic;
|
//if (baseObject["isStatic"] is bool isStatic) go.isStatic = isStatic;
|
||||||
return go;
|
return go;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region deprecated conversion functions
|
#region deprecated conversion functions
|
||||||
[Obsolete("Use " + nameof(RecursivelyConvertToNative_Coroutine))]
|
[Obsolete("Use " + nameof(RecursivelyConvertToNative_Coroutine))]
|
||||||
public IEnumerator ConvertCoroutine(Base rootObject, Transform? parent, List<GameObject> outCreatedObjects)
|
public IEnumerator ConvertCoroutine(
|
||||||
=> ConvertCoroutine(rootObject, parent, outCreatedObjects,b => ConverterInstance.CanConvertToNative(b));
|
Base rootObject,
|
||||||
|
Transform? parent,
|
||||||
|
List<GameObject> outCreatedObjects
|
||||||
|
) =>
|
||||||
|
ConvertCoroutine(
|
||||||
|
rootObject,
|
||||||
|
parent,
|
||||||
|
outCreatedObjects,
|
||||||
|
b => ConverterInstance.CanConvertToNative(b)
|
||||||
|
);
|
||||||
|
|
||||||
[Obsolete("Use " + nameof(RecursivelyConvertToNative_Coroutine))]
|
[Obsolete("Use " + nameof(RecursivelyConvertToNative_Coroutine))]
|
||||||
public IEnumerator ConvertCoroutine(Base rootObject, Transform? parent, List<GameObject> outCreatedObjects, Func<Base, bool> predicate)
|
public IEnumerator ConvertCoroutine(
|
||||||
|
Base rootObject,
|
||||||
|
Transform? parent,
|
||||||
|
List<GameObject> outCreatedObjects,
|
||||||
|
Func<Base, bool> predicate
|
||||||
|
)
|
||||||
{
|
{
|
||||||
foreach (string propertyName in GetPotentialChildren(rootObject))
|
foreach (string propertyName in GetPotentialChildren(rootObject))
|
||||||
{
|
{
|
||||||
|
@ -229,7 +267,7 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
yield return null;
|
yield return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Given <paramref name="o"/>,
|
/// Given <paramref name="o"/>,
|
||||||
/// will recursively convert any objects in the tree
|
/// will recursively convert any objects in the tree
|
||||||
|
@ -238,16 +276,20 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
/// <param name="parent">Optional parent transform for the created root <see cref="GameObject"/>s</param>
|
/// <param name="parent">Optional parent transform for the created root <see cref="GameObject"/>s</param>
|
||||||
/// <returns> A list of all created <see cref="GameObject"/>s</returns>
|
/// <returns> A list of all created <see cref="GameObject"/>s</returns>
|
||||||
[Obsolete("Use " + nameof(RecursivelyConvertToNative_Sync))]
|
[Obsolete("Use " + nameof(RecursivelyConvertToNative_Sync))]
|
||||||
public virtual List<GameObject> RecursivelyConvertToNative(object? o, Transform? parent)
|
public virtual List<GameObject> RecursivelyConvertToNative(object? o, Transform? parent) =>
|
||||||
=> RecursivelyConvertToNative(o, parent, b => ConverterInstance.CanConvertToNative(b));
|
RecursivelyConvertToNative(o, parent, b => ConverterInstance.CanConvertToNative(b));
|
||||||
|
|
||||||
/// <inheritdoc cref="RecursivelyConvertToNative(object, Transform)"/>
|
/// <inheritdoc cref="RecursivelyConvertToNative(object, Transform)"/>
|
||||||
/// <param name="predicate">A function to determine if an object should be converted</param>
|
/// <param name="predicate">A function to determine if an object should be converted</param>
|
||||||
[Obsolete("Use " + nameof(RecursivelyConvertToNative_Sync))]
|
[Obsolete("Use " + nameof(RecursivelyConvertToNative_Sync))]
|
||||||
public virtual List<GameObject> RecursivelyConvertToNative(object? o, Transform? parent, Func<Base, bool> predicate)
|
public virtual List<GameObject> RecursivelyConvertToNative(
|
||||||
|
object? o,
|
||||||
|
Transform? parent,
|
||||||
|
Func<Base, bool> predicate
|
||||||
|
)
|
||||||
{
|
{
|
||||||
InitializeAssetCache();
|
InitializeAssetCache();
|
||||||
|
|
||||||
var createdGameObjects = new List<GameObject>();
|
var createdGameObjects = new List<GameObject>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -260,10 +302,9 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO track event?
|
//TODO track event?
|
||||||
|
|
||||||
|
|
||||||
return createdGameObjects;
|
|
||||||
|
|
||||||
|
|
||||||
|
return createdGameObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeAssetCache()
|
private void InitializeAssetCache()
|
||||||
|
@ -277,10 +318,15 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
public virtual void RecurseTreeToNative(Base baseObject, Transform? parent, Func<Base, bool> predicate, IList<GameObject> outCreatedObjects)
|
public virtual void RecurseTreeToNative(
|
||||||
|
Base baseObject,
|
||||||
|
Transform? parent,
|
||||||
|
Func<Base, bool> predicate,
|
||||||
|
IList<GameObject> outCreatedObjects
|
||||||
|
)
|
||||||
{
|
{
|
||||||
object? converted = null;
|
object? converted = null;
|
||||||
if(predicate(baseObject))
|
if (predicate(baseObject))
|
||||||
converted = ConverterInstance.ConvertToNative(baseObject);
|
converted = ConverterInstance.ConvertToNative(baseObject);
|
||||||
|
|
||||||
// Handle new GameObjects
|
// Handle new GameObjects
|
||||||
|
@ -289,22 +335,23 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
{
|
{
|
||||||
outCreatedObjects.Add(go);
|
outCreatedObjects.Add(go);
|
||||||
nextParent = go.transform;
|
nextParent = go.transform;
|
||||||
|
|
||||||
go.transform.SetParent(parent, true);
|
go.transform.SetParent(parent, true);
|
||||||
|
|
||||||
//Set some common for all created GameObjects
|
//Set some common for all created GameObjects
|
||||||
//TODO add support for more unity specific props
|
//TODO add support for more unity specific props
|
||||||
if(go.name == "New Game Object" || string.IsNullOrWhiteSpace(go.name))
|
if (go.name == "New Game Object" || string.IsNullOrWhiteSpace(go.name))
|
||||||
go.name = CoreUtils.GenerateObjectName(baseObject);
|
go.name = CoreUtils.GenerateObjectName(baseObject);
|
||||||
//if (baseObject["tag"] is string t) go.tag = t;
|
//if (baseObject["tag"] is string t) go.tag = t;
|
||||||
if (baseObject["physicsLayer"] is string layerName)
|
if (baseObject["physicsLayer"] is string layerName)
|
||||||
{
|
{
|
||||||
int layer = LayerMask.NameToLayer(layerName); //TODO: check how this can be interoperable with Unreal and Blender
|
int layer = LayerMask.NameToLayer(layerName); //TODO: check how this can be interoperable with Unreal and Blender
|
||||||
if (layer > -1) go.layer = layer;
|
if (layer > -1)
|
||||||
|
go.layer = layer;
|
||||||
}
|
}
|
||||||
//if (baseObject["isStatic"] is bool isStatic) go.isStatic = isStatic;
|
//if (baseObject["isStatic"] is bool isStatic) go.isStatic = isStatic;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For geometry, only traverse `elements` prop, otherwise, try and convert everything
|
// For geometry, only traverse `elements` prop, otherwise, try and convert everything
|
||||||
IEnumerable<string> potentialChildren = GetPotentialChildren(baseObject);
|
IEnumerable<string> potentialChildren = GetPotentialChildren(baseObject);
|
||||||
|
|
||||||
|
@ -313,19 +360,23 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
{
|
{
|
||||||
ConvertChild(baseObject[propertyName], nextParent, predicate, outCreatedObjects);
|
ConvertChild(baseObject[propertyName], nextParent, predicate, outCreatedObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
private IEnumerable<string> GetPotentialChildren(Base baseObject)
|
private IEnumerable<string> GetPotentialChildren(Base baseObject)
|
||||||
{
|
{
|
||||||
return ConverterInstance.CanConvertToNative(baseObject)
|
return ConverterInstance.CanConvertToNative(baseObject)
|
||||||
? new []{"elements"}
|
? new[] { "elements" }
|
||||||
: baseObject.GetMembers().Keys;
|
: baseObject.GetMembers().Keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
protected virtual void ConvertChild(object? value, Transform? parent, Func<Base, bool> predicate, IList<GameObject> outCreatedObjects)
|
protected virtual void ConvertChild(
|
||||||
|
object? value,
|
||||||
|
Transform? parent,
|
||||||
|
Func<Base, bool> predicate,
|
||||||
|
IList<GameObject> outCreatedObjects
|
||||||
|
)
|
||||||
{
|
{
|
||||||
foreach (Base b in GraphTraversal.TraverseMember(value))
|
foreach (Base b in GraphTraversal.TraverseMember(value))
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,6 @@ using UnityEngine;
|
||||||
|
|
||||||
namespace Speckle.ConnectorUnity.Components
|
namespace Speckle.ConnectorUnity.Components
|
||||||
{
|
{
|
||||||
|
|
||||||
public partial class RecursiveConverter
|
public partial class RecursiveConverter
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -31,37 +30,44 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
/// <param name="rootObjects">Root objects of a tree</param>
|
/// <param name="rootObjects">Root objects of a tree</param>
|
||||||
/// <param name="predicate">A function to determine if an object should be converted</param>
|
/// <param name="predicate">A function to determine if an object should be converted</param>
|
||||||
/// <returns>A simple <see cref="Base"/> wrapping converted objects</returns>
|
/// <returns>A simple <see cref="Base"/> wrapping converted objects</returns>
|
||||||
public virtual Base RecursivelyConvertToSpeckle(IEnumerable<GameObject> rootObjects, Func<GameObject, bool> predicate)
|
public virtual Base RecursivelyConvertToSpeckle(
|
||||||
|
IEnumerable<GameObject> rootObjects,
|
||||||
|
Func<GameObject, bool> predicate
|
||||||
|
)
|
||||||
{
|
{
|
||||||
List<Base> convertedRootObjects = new List<Base>();
|
List<Base> convertedRootObjects = new List<Base>();
|
||||||
foreach (GameObject rootObject in rootObjects)
|
foreach (GameObject rootObject in rootObjects)
|
||||||
{
|
{
|
||||||
RecurseTreeToSpeckle(rootObject, predicate, convertedRootObjects);
|
RecurseTreeToSpeckle(rootObject, predicate, convertedRootObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Base()
|
return new Base() { ["@objects"] = convertedRootObjects, };
|
||||||
{
|
|
||||||
["@objects"] = convertedRootObjects,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Base RecursivelyConvertToSpeckle(GameObject rootObject, Func<GameObject, bool> predicate)
|
public virtual Base RecursivelyConvertToSpeckle(
|
||||||
|
GameObject rootObject,
|
||||||
|
Func<GameObject, bool> predicate
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return RecursivelyConvertToSpeckle(new[] {rootObject}, predicate);
|
return RecursivelyConvertToSpeckle(new[] { rootObject }, predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void RecurseTreeToSpeckle(GameObject currentObject, Func<GameObject, bool> predicate, List<Base> outConverted)
|
public virtual void RecurseTreeToSpeckle(
|
||||||
|
GameObject currentObject,
|
||||||
|
Func<GameObject, bool> predicate,
|
||||||
|
List<Base> outConverted
|
||||||
|
)
|
||||||
{
|
{
|
||||||
// Convert children first
|
// Convert children first
|
||||||
var convertedChildren = new List<Base>(currentObject.transform.childCount);
|
var convertedChildren = new List<Base>(currentObject.transform.childCount);
|
||||||
foreach(Transform child in currentObject.transform)
|
foreach (Transform child in currentObject.transform)
|
||||||
{
|
{
|
||||||
RecurseTreeToSpeckle(child.gameObject, predicate, convertedChildren);
|
RecurseTreeToSpeckle(child.gameObject, predicate, convertedChildren);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ConverterInstance.CanConvertToSpeckle(currentObject) && predicate(currentObject))
|
if (ConverterInstance.CanConvertToSpeckle(currentObject) && predicate(currentObject))
|
||||||
{
|
{
|
||||||
// Convert and output
|
// Convert and output
|
||||||
Base converted = ConverterInstance.ConvertToSpeckle(currentObject);
|
Base converted = ConverterInstance.ConvertToSpeckle(currentObject);
|
||||||
converted.SetDetachedPropertyChecked("elements", convertedChildren);
|
converted.SetDetachedPropertyChecked("elements", convertedChildren);
|
||||||
outConverted.Add(converted);
|
outConverted.Add(converted);
|
||||||
|
@ -71,7 +77,6 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
// Skip this object, and output any children
|
// Skip this object, and output any children
|
||||||
outConverted.AddRange(convertedChildren);
|
outConverted.AddRange(convertedChildren);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ using UnityEngine;
|
||||||
using UnityEngine.Events;
|
using UnityEngine.Events;
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("Speckle.ConnectorUnity.Components.Editor")]
|
[assembly: InternalsVisibleTo("Speckle.ConnectorUnity.Components.Editor")]
|
||||||
|
|
||||||
namespace Speckle.ConnectorUnity.Components
|
namespace Speckle.ConnectorUnity.Components
|
||||||
{
|
{
|
||||||
[ExecuteAlways]
|
[ExecuteAlways]
|
||||||
|
@ -28,13 +29,13 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
{
|
{
|
||||||
[field: SerializeReference]
|
[field: SerializeReference]
|
||||||
public AccountSelection Account { get; private set; }
|
public AccountSelection Account { get; private set; }
|
||||||
|
|
||||||
[field: SerializeReference]
|
[field: SerializeReference]
|
||||||
public StreamSelection Stream { get; private set; }
|
public StreamSelection Stream { get; private set; }
|
||||||
|
|
||||||
[field: SerializeReference]
|
[field: SerializeReference]
|
||||||
public BranchSelection Branch { get; private set; }
|
public BranchSelection Branch { get; private set; }
|
||||||
|
|
||||||
[field: SerializeReference]
|
[field: SerializeReference]
|
||||||
public CommitSelection Commit { get; private set; }
|
public CommitSelection Commit { get; private set; }
|
||||||
|
|
||||||
|
@ -44,12 +45,16 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
[Header("Events")]
|
[Header("Events")]
|
||||||
[HideInInspector]
|
[HideInInspector]
|
||||||
public CommitSelectionEvent OnCommitSelectionChange = new();
|
public CommitSelectionEvent OnCommitSelectionChange = new();
|
||||||
|
|
||||||
[HideInInspector]
|
[HideInInspector]
|
||||||
public OperationProgressEvent OnReceiveProgressAction = new();
|
public OperationProgressEvent OnReceiveProgressAction = new();
|
||||||
|
|
||||||
[HideInInspector]
|
[HideInInspector]
|
||||||
public ErrorActionEvent OnErrorAction = new();
|
public ErrorActionEvent OnErrorAction = new();
|
||||||
|
|
||||||
[HideInInspector]
|
[HideInInspector]
|
||||||
public ChildrenCountHandler OnTotalChildrenCountKnown = new();
|
public ChildrenCountHandler OnTotalChildrenCountKnown = new();
|
||||||
|
|
||||||
[HideInInspector]
|
[HideInInspector]
|
||||||
public ReceiveCompleteHandler OnComplete = new();
|
public ReceiveCompleteHandler OnComplete = new();
|
||||||
|
|
||||||
|
@ -66,11 +71,12 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
/// <returns><see langword="true"/> if the cancellation request was made. <see langword="false"/> if there was no pending operation to cancel (see <see cref="IsReceiving"/>)</returns>
|
/// <returns><see langword="true"/> if the cancellation request was made. <see langword="false"/> if there was no pending operation to cancel (see <see cref="IsReceiving"/>)</returns>
|
||||||
public bool Cancel()
|
public bool Cancel()
|
||||||
{
|
{
|
||||||
if (CancellationTokenSource == null) return false;
|
if (CancellationTokenSource == null)
|
||||||
|
return false;
|
||||||
CancellationTokenSource.Cancel();
|
CancellationTokenSource.Cancel();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Receive the selected <see cref="Commit"/> object, and converts ToNative as children of <paramref name="parent"/>
|
/// Receive the selected <see cref="Commit"/> object, and converts ToNative as children of <paramref name="parent"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -79,17 +85,23 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
/// <remarks>function does not throw, instead calls <see cref="OnErrorAction"/>, and calls <see cref="OnComplete"/> upon completion</remarks>
|
/// <remarks>function does not throw, instead calls <see cref="OnErrorAction"/>, and calls <see cref="OnComplete"/> upon completion</remarks>
|
||||||
/// <seealso cref="ReceiveAsync(System.Threading.CancellationToken)"/>
|
/// <seealso cref="ReceiveAsync(System.Threading.CancellationToken)"/>
|
||||||
/// <seealso cref="RecursiveConverter.RecursivelyConvertToNative_Enumerable"/>
|
/// <seealso cref="RecursiveConverter.RecursivelyConvertToNative_Enumerable"/>
|
||||||
public IEnumerator ReceiveAndConvert_Routine(Transform? parent, Predicate<TraversalContext>? predicate = null)
|
public IEnumerator ReceiveAndConvert_Routine(
|
||||||
|
Transform? parent,
|
||||||
|
Predicate<TraversalContext>? predicate = null
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (IsReceiving)
|
if (IsReceiving)
|
||||||
{
|
{
|
||||||
OnErrorAction.Invoke("Failed to receive", new InvalidOperationException("A pending receive operation has already started"));
|
OnErrorAction.Invoke(
|
||||||
|
"Failed to receive",
|
||||||
|
new InvalidOperationException("A pending receive operation has already started")
|
||||||
|
);
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
CancellationTokenSource?.Dispose();
|
CancellationTokenSource?.Dispose();
|
||||||
CancellationTokenSource = new();
|
CancellationTokenSource = new();
|
||||||
|
|
||||||
// ReSharper disable once MethodSupportsCancellation
|
// ReSharper disable once MethodSupportsCancellation
|
||||||
Task<Base> receiveOperation = Task.Run(async () =>
|
Task<Base> receiveOperation = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
|
@ -97,7 +109,7 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
CancellationToken.ThrowIfCancellationRequested();
|
CancellationToken.ThrowIfCancellationRequested();
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
yield return new WaitUntil(() => receiveOperation.IsCompleted);
|
yield return new WaitUntil(() => receiveOperation.IsCompleted);
|
||||||
|
|
||||||
if (receiveOperation.IsFaulted)
|
if (receiveOperation.IsFaulted)
|
||||||
|
@ -106,7 +118,7 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
FinishOperation();
|
FinishOperation();
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Base b = receiveOperation.Result;
|
Base b = receiveOperation.Result;
|
||||||
|
|
||||||
foreach (var _ in Converter.RecursivelyConvertToNative_Enumerable(b, parent, predicate))
|
foreach (var _ in Converter.RecursivelyConvertToNative_Enumerable(b, parent, predicate))
|
||||||
|
@ -118,9 +130,11 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
FinishOperation();
|
FinishOperation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <inheritdoc cref="ReceiveAndConvert_Routine"/>
|
/// <inheritdoc cref="ReceiveAndConvert_Routine"/>
|
||||||
public async void ReceiveAndConvert_Async(Transform? parent, Predicate<TraversalContext>? predicate = null)
|
public async void ReceiveAndConvert_Async(
|
||||||
|
Transform? parent,
|
||||||
|
Predicate<TraversalContext>? predicate = null
|
||||||
|
)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -154,7 +168,7 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
public async Task<Base> ReceiveAsync(CancellationToken cancellationToken)
|
public async Task<Base> ReceiveAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
ValidateSelection(out Client? client, out Stream? stream, out Commit? commit);
|
ValidateSelection(out Client? client, out Stream? stream, out Commit? commit);
|
||||||
|
|
||||||
Base result = await ReceiveAsync(
|
Base result = await ReceiveAsync(
|
||||||
|
@ -167,20 +181,23 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
cancellationToken: cancellationToken
|
cancellationToken: cancellationToken
|
||||||
)
|
)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ValidateSelection(out Client client, out Stream stream, out Commit commit)
|
public void ValidateSelection(out Client client, out Stream stream, out Commit commit)
|
||||||
{
|
{
|
||||||
Client? selectedClient = Account.Client;
|
Client? selectedClient = Account.Client;
|
||||||
client = selectedClient ?? throw new InvalidOperationException("Invalid account selection");
|
client =
|
||||||
|
selectedClient ?? throw new InvalidOperationException("Invalid account selection");
|
||||||
|
|
||||||
Stream? selectedStream = Stream.Selected;
|
Stream? selectedStream = Stream.Selected;
|
||||||
stream = selectedStream ?? throw new InvalidOperationException("Invalid stream selection");
|
stream =
|
||||||
|
selectedStream ?? throw new InvalidOperationException("Invalid stream selection");
|
||||||
|
|
||||||
Commit? selectedCommit = Commit.Selected;
|
Commit? selectedCommit = Commit.Selected;
|
||||||
commit = selectedCommit ?? throw new InvalidOperationException("Invalid commit selection");
|
commit =
|
||||||
|
selectedCommit ?? throw new InvalidOperationException("Invalid commit selection");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -189,22 +206,26 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
/// <exception cref="InvalidOperationException">already receiving</exception>
|
/// <exception cref="InvalidOperationException">already receiving</exception>
|
||||||
protected internal CancellationToken BeginOperation()
|
protected internal CancellationToken BeginOperation()
|
||||||
{
|
{
|
||||||
if (IsReceiving) throw new InvalidOperationException("A pending receive operation has already started");
|
if (IsReceiving)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"A pending receive operation has already started"
|
||||||
|
);
|
||||||
|
|
||||||
CancellationTokenSource?.Dispose();
|
CancellationTokenSource?.Dispose();
|
||||||
CancellationTokenSource = new();
|
CancellationTokenSource = new();
|
||||||
|
|
||||||
return CancellationTokenSource.Token;
|
return CancellationTokenSource.Token;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected internal void FinishOperation()
|
protected internal void FinishOperation()
|
||||||
{
|
{
|
||||||
if (!IsReceiving) throw new InvalidOperationException("No pending operations to finish");
|
if (!IsReceiving)
|
||||||
|
throw new InvalidOperationException("No pending operations to finish");
|
||||||
|
|
||||||
CancellationTokenSource!.Dispose();
|
CancellationTokenSource!.Dispose();
|
||||||
CancellationTokenSource = null;
|
CancellationTokenSource = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Receives the requested <see cref="objectId"/> using async Task
|
/// Receives the requested <see cref="objectId"/> using async Task
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -223,64 +244,90 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
string objectId,
|
string objectId,
|
||||||
Commit? commit,
|
Commit? commit,
|
||||||
Action<ConcurrentDictionary<string, int>>? onProgressAction = null,
|
Action<ConcurrentDictionary<string, int>>? onProgressAction = null,
|
||||||
Action<int>? onTotalChildrenCountKnown = null,
|
Action<int>? onTotalChildrenCountKnown = null,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default
|
||||||
|
)
|
||||||
{
|
{
|
||||||
using var transport = new ServerTransportV2(client.Account, streamId);
|
using var transport = new ServerTransportV2(client.Account, streamId);
|
||||||
|
|
||||||
transport.CancellationToken = cancellationToken;
|
transport.CancellationToken = cancellationToken;
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
Base? requestedObject = await Operations.Receive(
|
Base? requestedObject = await Operations
|
||||||
objectId: objectId,
|
.Receive(
|
||||||
cancellationToken: cancellationToken,
|
objectId: objectId,
|
||||||
remoteTransport: transport,
|
cancellationToken: cancellationToken,
|
||||||
onProgressAction: onProgressAction,
|
remoteTransport: transport,
|
||||||
onErrorAction: (s, ex) =>
|
onProgressAction: onProgressAction,
|
||||||
{
|
onErrorAction: (s, ex) =>
|
||||||
//Don't wrap cancellation exceptions!
|
|
||||||
if (ex is OperationCanceledException)
|
|
||||||
throw ex;
|
|
||||||
|
|
||||||
//HACK: Sometimes, the task was cancelled, and Operations.Receive doesn't fail in a reliable way. In this case, the exception is often simply a symptom of a cancel.
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
{
|
||||||
SpeckleLog.Logger.Warning(ex, "A task was cancelled, ignoring potentially symptomatic exception");
|
//Don't wrap cancellation exceptions!
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
if (ex is OperationCanceledException)
|
||||||
}
|
throw ex;
|
||||||
|
|
||||||
//Treat all operation errors as fatal
|
//HACK: Sometimes, the task was cancelled, and Operations.Receive doesn't fail in a reliable way. In this case, the exception is often simply a symptom of a cancel.
|
||||||
throw new SpeckleException($"Failed to receive requested object {objectId} from server: {s}", ex);
|
if (cancellationToken.IsCancellationRequested)
|
||||||
},
|
{
|
||||||
onTotalChildrenCountKnown: onTotalChildrenCountKnown,
|
SpeckleLog.Logger.Warning(
|
||||||
disposeTransports: false
|
ex,
|
||||||
).ConfigureAwait(false);
|
"A task was cancelled, ignoring potentially symptomatic exception"
|
||||||
|
);
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Treat all operation errors as fatal
|
||||||
|
throw new SpeckleException(
|
||||||
|
$"Failed to receive requested object {objectId} from server: {s}",
|
||||||
|
ex
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onTotalChildrenCountKnown: onTotalChildrenCountKnown,
|
||||||
|
disposeTransports: false
|
||||||
|
)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
Analytics.TrackEvent(
|
||||||
|
client.Account,
|
||||||
|
Analytics.Events.Receive,
|
||||||
|
new Dictionary<string, object>()
|
||||||
|
{
|
||||||
|
{ "mode", nameof(SpeckleReceiver) },
|
||||||
|
{
|
||||||
|
"sourceHostApp",
|
||||||
|
HostApplications.GetHostAppFromString(commit?.sourceApplication).Slug
|
||||||
|
},
|
||||||
|
{ "sourceHostAppVersion", commit?.sourceApplication ?? "" },
|
||||||
|
{ "hostPlatform", Application.platform.ToString() },
|
||||||
|
{
|
||||||
|
"isMultiplayer",
|
||||||
|
commit != null && commit.authorId != client.Account.userInfo.id
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
Analytics.TrackEvent(client.Account, Analytics.Events.Receive, new Dictionary<string, object>()
|
|
||||||
{
|
|
||||||
{"mode", nameof(SpeckleReceiver)},
|
|
||||||
{"sourceHostApp", HostApplications.GetHostAppFromString(commit?.sourceApplication).Slug},
|
|
||||||
{"sourceHostAppVersion", commit?.sourceApplication ?? ""},
|
|
||||||
{"hostPlatform", Application.platform.ToString()},
|
|
||||||
{"isMultiplayer", commit != null && commit.authorId != client.Account.userInfo.id},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (requestedObject == null)
|
if (requestedObject == null)
|
||||||
throw new SpeckleException($"Operation {nameof(Operations.Receive)} returned null");
|
throw new SpeckleException($"Operation {nameof(Operations.Receive)} returned null");
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
//Read receipt
|
//Read receipt
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await client.CommitReceived(cancellationToken, new CommitReceivedInput
|
await client
|
||||||
{
|
.CommitReceived(
|
||||||
streamId = streamId,
|
cancellationToken,
|
||||||
commitId = commit?.id,
|
new CommitReceivedInput
|
||||||
message = $"received commit from {Application.unityVersion}",
|
{
|
||||||
sourceApplication = HostApplications.Unity.GetVersion(CoreUtils.GetHostAppVersion())
|
streamId = streamId,
|
||||||
}).ConfigureAwait(false);
|
commitId = commit?.id,
|
||||||
|
message = $"received commit from {Application.unityVersion}",
|
||||||
|
sourceApplication = HostApplications.Unity.GetVersion(
|
||||||
|
CoreUtils.GetHostAppVersion()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -299,9 +346,18 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
/// <param name="rootObjectName">The name of the parent <see cref="GameObject"/> to create</param>
|
/// <param name="rootObjectName">The name of the parent <see cref="GameObject"/> to create</param>
|
||||||
/// <param name="beforeConvertCallback">Callback for each object converted</param>
|
/// <param name="beforeConvertCallback">Callback for each object converted</param>
|
||||||
/// <returns>The created parent <see cref="GameObject"/></returns>
|
/// <returns>The created parent <see cref="GameObject"/></returns>
|
||||||
[Obsolete("Use " + nameof(RecursiveConverter) + " Now we have implemented support for " + nameof(Collection) + "s, receiving any collection is now the default behaviour")]
|
[Obsolete(
|
||||||
public GameObject ConvertToNativeWithCategories(Base @base, string rootObjectName,
|
"Use "
|
||||||
Action<Base>? beforeConvertCallback)
|
+ nameof(RecursiveConverter)
|
||||||
|
+ " Now we have implemented support for "
|
||||||
|
+ nameof(Collection)
|
||||||
|
+ "s, receiving any collection is now the default behaviour"
|
||||||
|
)]
|
||||||
|
public GameObject ConvertToNativeWithCategories(
|
||||||
|
Base @base,
|
||||||
|
string rootObjectName,
|
||||||
|
Action<Base>? beforeConvertCallback
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var rootObject = new GameObject(rootObjectName);
|
var rootObject = new GameObject(rootObjectName);
|
||||||
|
|
||||||
|
@ -309,10 +365,9 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
{
|
{
|
||||||
beforeConvertCallback?.Invoke(o);
|
beforeConvertCallback?.Invoke(o);
|
||||||
return Converter.ConverterInstance.CanConvertToNative(o) //Accept geometry
|
return Converter.ConverterInstance.CanConvertToNative(o) //Accept geometry
|
||||||
|| o.speckle_type == nameof(Base) && o.totalChildrenCount > 0; // Or Base objects that have children
|
|| o.speckle_type == nameof(Base) && o.totalChildrenCount > 0; // Or Base objects that have children
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// For the rootObject only, we will create property GameObjects
|
// For the rootObject only, we will create property GameObjects
|
||||||
// i.e. revit categories
|
// i.e. revit categories
|
||||||
foreach (var prop in @base.GetMembers())
|
foreach (var prop in @base.GetMembers())
|
||||||
|
@ -320,21 +375,23 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
var converted = Converter.RecursivelyConvertToNative(prop.Value, null, Predicate);
|
var converted = Converter.RecursivelyConvertToNative(prop.Value, null, Predicate);
|
||||||
|
|
||||||
//Skip empties
|
//Skip empties
|
||||||
if (converted.Count <= 0) continue;
|
if (converted.Count <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
var propertyObject = new GameObject(prop.Key);
|
var propertyObject = new GameObject(prop.Key);
|
||||||
propertyObject.transform.SetParent(rootObject.transform);
|
propertyObject.transform.SetParent(rootObject.transform);
|
||||||
foreach (var o in converted)
|
foreach (var o in converted)
|
||||||
{
|
{
|
||||||
if (o.transform.parent == null) o.transform.SetParent(propertyObject.transform);
|
if (o.transform.parent == null)
|
||||||
|
o.transform.SetParent(propertyObject.transform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rootObject;
|
return rootObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="client"></param>
|
/// <param name="client"></param>
|
||||||
/// <param name="stream"></param>
|
/// <param name="stream"></param>
|
||||||
|
@ -346,27 +403,28 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
[NotNullWhen(true)] out Client? client,
|
[NotNullWhen(true)] out Client? client,
|
||||||
[NotNullWhen(true)] out Stream? stream,
|
[NotNullWhen(true)] out Stream? stream,
|
||||||
[NotNullWhen(true)] out Commit? commit,
|
[NotNullWhen(true)] out Commit? commit,
|
||||||
[NotNullWhen(false)] out string? error)
|
[NotNullWhen(false)] out string? error
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Account? account = Account.Selected;
|
Account? account = Account.Selected;
|
||||||
stream = Stream.Selected;
|
stream = Stream.Selected;
|
||||||
commit = Commit.Selected;
|
commit = Commit.Selected;
|
||||||
|
|
||||||
if (account == null)
|
if (account == null)
|
||||||
{
|
{
|
||||||
error = "Selected Account is null";
|
error = "Selected Account is null";
|
||||||
client = null;
|
client = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
client = Account.Client ?? new Client(account);
|
client = Account.Client ?? new Client(account);
|
||||||
|
|
||||||
if (stream == null)
|
if (stream == null)
|
||||||
{
|
{
|
||||||
error = "Selected Stream is null";
|
error = "Selected Stream is null";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commit == null)
|
if (commit == null)
|
||||||
{
|
{
|
||||||
error = "Selected Commit is null";
|
error = "Selected Commit is null";
|
||||||
return false;
|
return false;
|
||||||
|
@ -374,29 +432,35 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
error = null;
|
error = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fetches the commit preview for the currently selected commit
|
/// Fetches the commit preview for the currently selected commit
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="allAngles">when <see langword="true"/>, will fetch 360 degree preview image</param>
|
/// <param name="allAngles">when <see langword="true"/>, will fetch 360 degree preview image</param>
|
||||||
/// <param name="callback">Callback function to be called when the web request completes</param>
|
/// <param name="callback">Callback function to be called when the web request completes</param>
|
||||||
/// <returns>The executing <see cref="Coroutine"/> or <see langword="null"/> if <see cref="Account"/>, <see cref="Stream"/>, or <see cref="Commit"/> was <see langword="null"/></returns>
|
/// <returns>The executing <see cref="Coroutine"/> or <see langword="null"/> if <see cref="Account"/>, <see cref="Stream"/>, or <see cref="Commit"/> was <see langword="null"/></returns>
|
||||||
public Coroutine? GetPreviewImage(/*bool allAngles,*/ Action<Texture2D?> callback)
|
public Coroutine? GetPreviewImage( /*bool allAngles,*/
|
||||||
|
Action<Texture2D?> callback
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Account? account = Account.Selected;
|
Account? account = Account.Selected;
|
||||||
if (account == null) return null;
|
if (account == null)
|
||||||
|
return null;
|
||||||
string? streamId = Stream.Selected?.id;
|
string? streamId = Stream.Selected?.id;
|
||||||
if (streamId == null) return null;
|
if (streamId == null)
|
||||||
|
return null;
|
||||||
string? commitId = Commit.Selected?.id;
|
string? commitId = Commit.Selected?.id;
|
||||||
if (commitId == null) return null;
|
if (commitId == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
string angles = /*allAngles ? "all" :*/ "";
|
string angles = /*allAngles ? "all" :*/
|
||||||
|
"";
|
||||||
string url = $"{account.serverInfo.url}/preview/{streamId}/commits/{commitId}/{angles}";
|
string url = $"{account.serverInfo.url}/preview/{streamId}/commits/{commitId}/{angles}";
|
||||||
string authToken = account.token;
|
string authToken = account.token;
|
||||||
|
|
||||||
return StartCoroutine(Utils.Utils.GetImageRoutine(url, authToken, callback));
|
return StartCoroutine(Utils.Utils.GetImageRoutine(url, authToken, callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
[ContextMenu("Open Speckle Stream in Browser")]
|
[ContextMenu("Open Speckle Stream in Browser")]
|
||||||
protected void OpenUrlInBrowser()
|
protected void OpenUrlInBrowser()
|
||||||
|
@ -405,8 +469,7 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
Application.OpenURL(url);
|
Application.OpenURL(url);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
public string GetSelectedUrl()
|
public string GetSelectedUrl()
|
||||||
{
|
{
|
||||||
string serverUrl = Account.Selected!.serverInfo.url;
|
string serverUrl = Account.Selected!.serverInfo.url;
|
||||||
|
@ -414,12 +477,15 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
string? branchName = Branch.Selected?.name;
|
string? branchName = Branch.Selected?.name;
|
||||||
string? commitId = Commit.Selected?.id;
|
string? commitId = Commit.Selected?.id;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(streamId)) return serverUrl;
|
if (string.IsNullOrEmpty(streamId))
|
||||||
if (!string.IsNullOrEmpty(commitId)) return $"{serverUrl}/streams/{streamId}/commits/{commitId}";
|
return serverUrl;
|
||||||
if (!string.IsNullOrEmpty(branchName)) return $"{serverUrl}/streams/{streamId}/branches/{branchName}";
|
if (!string.IsNullOrEmpty(commitId))
|
||||||
|
return $"{serverUrl}/streams/{streamId}/commits/{commitId}";
|
||||||
|
if (!string.IsNullOrEmpty(branchName))
|
||||||
|
return $"{serverUrl}/streams/{streamId}/branches/{branchName}";
|
||||||
return $"{serverUrl}/streams/{streamId}";
|
return $"{serverUrl}/streams/{streamId}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Awake()
|
public void Awake()
|
||||||
{
|
{
|
||||||
Converter = GetComponent<RecursiveConverter>();
|
Converter = GetComponent<RecursiveConverter>();
|
||||||
|
@ -436,12 +502,11 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
Stream.Initialise();
|
Stream.Initialise();
|
||||||
Branch.Initialise();
|
Branch.Initialise();
|
||||||
Commit.Initialise();
|
Commit.Initialise();
|
||||||
Commit.OnSelectionChange =
|
Commit.OnSelectionChange = () => OnCommitSelectionChange?.Invoke(Commit.Selected);
|
||||||
() => OnCommitSelectionChange?.Invoke(Commit.Selected);
|
if (Account.Options is not { Length: > 0 } || forceRefresh)
|
||||||
if(Account.Options is not {Length: > 0} || forceRefresh)
|
|
||||||
Account.RefreshOptions();
|
Account.RefreshOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnDisable()
|
public void OnDisable()
|
||||||
{
|
{
|
||||||
CancellationTokenSource?.Cancel();
|
CancellationTokenSource?.Cancel();
|
||||||
|
@ -456,36 +521,54 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
{
|
{
|
||||||
//pass
|
//pass
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnAfterDeserialize()
|
public void OnAfterDeserialize()
|
||||||
{
|
{
|
||||||
Initialise();
|
Initialise();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Deprecated members
|
#region Deprecated members
|
||||||
|
|
||||||
[Obsolete("use " + nameof(ReceiveAndConvertRoutine), true)]
|
[Obsolete("use " + nameof(ReceiveAndConvertRoutine), true)]
|
||||||
public IEnumerator ReceiveAndConvertRoutine(SpeckleReceiver speckleReceiver, string rootObjectName, Action<Base>? beforeConvertCallback = null)
|
public IEnumerator ReceiveAndConvertRoutine(
|
||||||
|
SpeckleReceiver speckleReceiver,
|
||||||
|
string rootObjectName,
|
||||||
|
Action<Base>? beforeConvertCallback = null
|
||||||
|
)
|
||||||
{
|
{
|
||||||
// ReSharper disable once MethodSupportsCancellation
|
// ReSharper disable once MethodSupportsCancellation
|
||||||
Task<Base> receiveOperation = Task.Run(async () => await ReceiveAsync(CancellationToken));
|
Task<Base> receiveOperation = Task.Run(
|
||||||
|
async () => await ReceiveAsync(CancellationToken)
|
||||||
|
);
|
||||||
|
|
||||||
yield return new WaitUntil(() => receiveOperation.IsCompleted);
|
yield return new WaitUntil(() => receiveOperation.IsCompleted);
|
||||||
|
|
||||||
Base? b = receiveOperation.Result;
|
Base? b = receiveOperation.Result;
|
||||||
if (b == null) yield break;
|
if (b == null)
|
||||||
|
yield break;
|
||||||
//NOTE: coroutine doesn't break for each catergory/object
|
|
||||||
GameObject go = ConvertToNativeWithCategories(b, rootObjectName, beforeConvertCallback);
|
|
||||||
|
|
||||||
|
//NOTE: coroutine doesn't break for each catergory/object
|
||||||
|
ConvertToNativeWithCategories(b, rootObjectName, beforeConvertCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable] public sealed class CommitSelectionEvent : UnityEvent<Commit?> { }
|
[Serializable]
|
||||||
[Serializable] public sealed class BranchSelectionEvent : UnityEvent<Branch?> { }
|
public sealed class CommitSelectionEvent : UnityEvent<Commit?> { }
|
||||||
[Serializable] public sealed class ErrorActionEvent : UnityEvent<string, Exception> { }
|
|
||||||
[Serializable] public sealed class OperationProgressEvent : UnityEvent<ConcurrentDictionary<string, int>> { }
|
[Serializable]
|
||||||
[Serializable] public sealed class ReceiveCompleteHandler : UnityEvent<Transform?> { }
|
public sealed class BranchSelectionEvent : UnityEvent<Branch?> { }
|
||||||
[Serializable] public sealed class ChildrenCountHandler : UnityEvent<int> { }
|
|
||||||
|
[Serializable]
|
||||||
|
public sealed class ErrorActionEvent : UnityEvent<string, Exception> { }
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public sealed class OperationProgressEvent : UnityEvent<ConcurrentDictionary<string, int>> { }
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public sealed class ReceiveCompleteHandler : UnityEvent<Transform?> { }
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public sealed class ChildrenCountHandler : UnityEvent<int> { }
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,39 +23,49 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
{
|
{
|
||||||
[field: SerializeReference]
|
[field: SerializeReference]
|
||||||
public AccountSelection Account { get; private set; }
|
public AccountSelection Account { get; private set; }
|
||||||
|
|
||||||
[field: SerializeReference]
|
[field: SerializeReference]
|
||||||
public StreamSelection Stream { get; private set; }
|
public StreamSelection Stream { get; private set; }
|
||||||
|
|
||||||
[field: SerializeReference]
|
[field: SerializeReference]
|
||||||
public BranchSelection Branch { get; private set; }
|
public BranchSelection Branch { get; private set; }
|
||||||
|
|
||||||
public RecursiveConverter Converter { get; private set; }
|
public RecursiveConverter Converter { get; private set; }
|
||||||
|
|
||||||
[Header("Events")]
|
[Header("Events")]
|
||||||
[HideInInspector]
|
[HideInInspector]
|
||||||
public BranchSelectionEvent OnBranchSelectionChange;
|
public BranchSelectionEvent OnBranchSelectionChange;
|
||||||
|
|
||||||
[HideInInspector]
|
[HideInInspector]
|
||||||
public ErrorActionEvent OnErrorAction;
|
public ErrorActionEvent OnErrorAction;
|
||||||
|
|
||||||
[HideInInspector]
|
[HideInInspector]
|
||||||
public OperationProgressEvent OnSendProgressAction;
|
public OperationProgressEvent OnSendProgressAction;
|
||||||
#nullable enable
|
#nullable enable
|
||||||
protected internal CancellationTokenSource? CancellationTokenSource { get; private set; }
|
protected internal CancellationTokenSource? CancellationTokenSource { get; private set; }
|
||||||
|
|
||||||
//TODO runtime sending
|
//TODO runtime sending
|
||||||
|
|
||||||
public async Task<string> SendDataAsync(Base data, bool createCommit)
|
public async Task<string> SendDataAsync(Base data, bool createCommit)
|
||||||
{
|
{
|
||||||
CancellationTokenSource?.Cancel();
|
CancellationTokenSource?.Cancel();
|
||||||
CancellationTokenSource?.Dispose();
|
CancellationTokenSource?.Dispose();
|
||||||
CancellationTokenSource = new CancellationTokenSource();
|
CancellationTokenSource = new CancellationTokenSource();
|
||||||
if(!GetSelection(out Client? client, out Stream? stream, out Branch? branch, out string? error))
|
if (
|
||||||
|
!GetSelection(
|
||||||
|
out Client? client,
|
||||||
|
out Stream? stream,
|
||||||
|
out Branch? branch,
|
||||||
|
out string? error
|
||||||
|
)
|
||||||
|
)
|
||||||
throw new SpeckleException(error);
|
throw new SpeckleException(error);
|
||||||
|
|
||||||
ServerTransport transport = new ServerTransport(client.Account, stream.id);
|
ServerTransport transport = new ServerTransport(client.Account, stream.id);
|
||||||
transport.CancellationToken = CancellationTokenSource.Token;
|
transport.CancellationToken = CancellationTokenSource.Token;
|
||||||
|
|
||||||
return await SendDataAsync(CancellationTokenSource.Token,
|
return await SendDataAsync(
|
||||||
|
CancellationTokenSource.Token,
|
||||||
remoteTransport: transport,
|
remoteTransport: transport,
|
||||||
data: data,
|
data: data,
|
||||||
client: client,
|
client: client,
|
||||||
|
@ -66,93 +76,114 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<string> SendDataAsync(CancellationToken cancellationToken,
|
public static async Task<string> SendDataAsync(
|
||||||
|
CancellationToken cancellationToken,
|
||||||
ServerTransport remoteTransport,
|
ServerTransport remoteTransport,
|
||||||
Base data,
|
Base data,
|
||||||
Client client,
|
Client client,
|
||||||
string branchName,
|
string branchName,
|
||||||
bool createCommit,
|
bool createCommit,
|
||||||
Action<ConcurrentDictionary<string, int>>? onProgressAction = null,
|
Action<ConcurrentDictionary<string, int>>? onProgressAction = null,
|
||||||
Action<string, Exception>? onErrorAction = null)
|
Action<string, Exception>? onErrorAction = null
|
||||||
|
)
|
||||||
{
|
{
|
||||||
string res = await Operations.Send(
|
string res = await Operations.Send(
|
||||||
data,
|
data,
|
||||||
cancellationToken: cancellationToken,
|
cancellationToken: cancellationToken,
|
||||||
new List<ITransport>{remoteTransport},
|
new List<ITransport> { remoteTransport },
|
||||||
useDefaultCache: true,
|
useDefaultCache: true,
|
||||||
disposeTransports: true,
|
disposeTransports: true,
|
||||||
onProgressAction: onProgressAction,
|
onProgressAction: onProgressAction,
|
||||||
onErrorAction: onErrorAction
|
onErrorAction: onErrorAction
|
||||||
);
|
);
|
||||||
|
|
||||||
Analytics.TrackEvent(client.Account, Analytics.Events.Send, new Dictionary<string, object>()
|
Analytics.TrackEvent(
|
||||||
{
|
client.Account,
|
||||||
{"mode", nameof(SpeckleSender)},
|
Analytics.Events.Send,
|
||||||
{"hostPlatform", Application.platform.ToString()},
|
new Dictionary<string, object>()
|
||||||
});
|
{
|
||||||
|
{ "mode", nameof(SpeckleSender) },
|
||||||
|
{ "hostPlatform", Application.platform.ToString() },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (createCommit && !cancellationToken.IsCancellationRequested)
|
if (createCommit && !cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
string streamId = remoteTransport.StreamId;
|
string streamId = remoteTransport.StreamId;
|
||||||
string unityVer = $"Unity {Application.unityVersion.Substring(0,6)}";
|
string unityVer = $"Unity {Application.unityVersion.Substring(0, 6)}";
|
||||||
data.totalChildrenCount = data.GetTotalChildrenCount();
|
data.totalChildrenCount = data.GetTotalChildrenCount();
|
||||||
string commitMessage = $"Sent {data.totalChildrenCount} objects from {unityVer}";
|
string commitMessage = $"Sent {data.totalChildrenCount} objects from {unityVer}";
|
||||||
|
|
||||||
string commitId = await CreateCommit(cancellationToken, data, client, streamId, branchName, res, commitMessage);
|
string commitId = await CreateCommit(
|
||||||
|
cancellationToken,
|
||||||
|
data,
|
||||||
|
client,
|
||||||
|
streamId,
|
||||||
|
branchName,
|
||||||
|
res,
|
||||||
|
commitMessage
|
||||||
|
);
|
||||||
string url = $"{client.ServerUrl}/streams/{streamId}/commits/{commitId}";
|
string url = $"{client.ServerUrl}/streams/{streamId}/commits/{commitId}";
|
||||||
Debug.Log($"Data successfully sent to <a href=\"{url}\">{url}</a>");
|
Debug.Log($"Data successfully sent to <a href=\"{url}\">{url}</a>");
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<string> CreateCommit(CancellationToken cancellationToken,
|
public static async Task<string> CreateCommit(
|
||||||
|
CancellationToken cancellationToken,
|
||||||
Base data,
|
Base data,
|
||||||
Client client,
|
Client client,
|
||||||
string streamId,
|
string streamId,
|
||||||
string branchName,
|
string branchName,
|
||||||
string objectId,
|
string objectId,
|
||||||
string message)
|
string message
|
||||||
|
)
|
||||||
{
|
{
|
||||||
string commitId = await client.CommitCreate(cancellationToken,
|
string commitId = await client.CommitCreate(
|
||||||
|
cancellationToken,
|
||||||
new CommitCreateInput
|
new CommitCreateInput
|
||||||
{
|
{
|
||||||
streamId = streamId,
|
streamId = streamId,
|
||||||
branchName = branchName,
|
branchName = branchName,
|
||||||
objectId = objectId,
|
objectId = objectId,
|
||||||
message = message,
|
message = message,
|
||||||
sourceApplication = HostApplications.Unity.GetVersion(CoreUtils.GetHostAppVersion()),
|
sourceApplication = HostApplications.Unity.GetVersion(
|
||||||
|
CoreUtils.GetHostAppVersion()
|
||||||
|
),
|
||||||
totalChildrenCount = (int)data.totalChildrenCount,
|
totalChildrenCount = (int)data.totalChildrenCount,
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return commitId;
|
return commitId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool GetSelection(
|
public bool GetSelection(
|
||||||
[NotNullWhen(true)] out Client? client,
|
[NotNullWhen(true)] out Client? client,
|
||||||
[NotNullWhen(true)] out Stream? stream,
|
[NotNullWhen(true)] out Stream? stream,
|
||||||
[NotNullWhen(true)] out Branch? branch,
|
[NotNullWhen(true)] out Branch? branch,
|
||||||
[NotNullWhen(false)] out string? error)
|
[NotNullWhen(false)] out string? error
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Account? account = Account.Selected;
|
Account? account = Account.Selected;
|
||||||
stream = Stream.Selected;
|
stream = Stream.Selected;
|
||||||
branch = Branch.Selected;
|
branch = Branch.Selected;
|
||||||
|
|
||||||
if (account == null)
|
if (account == null)
|
||||||
{
|
{
|
||||||
error = "Selected Account is null";
|
error = "Selected Account is null";
|
||||||
client = null;
|
client = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
client = Account.Client ?? new Client(account);
|
client = Account.Client ?? new Client(account);
|
||||||
|
|
||||||
if (stream == null)
|
if (stream == null)
|
||||||
{
|
{
|
||||||
error = "Selected Stream is null";
|
error = "Selected Stream is null";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (branch == null)
|
if (branch == null)
|
||||||
{
|
{
|
||||||
error = "Selected Branch is null";
|
error = "Selected Branch is null";
|
||||||
return false;
|
return false;
|
||||||
|
@ -160,8 +191,7 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
error = null;
|
error = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
[ContextMenu("Open Speckle Stream in Browser")]
|
[ContextMenu("Open Speckle Stream in Browser")]
|
||||||
protected void OpenUrlInBrowser()
|
protected void OpenUrlInBrowser()
|
||||||
|
@ -170,24 +200,26 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
Application.OpenURL(url);
|
Application.OpenURL(url);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public string GetSelectedUrl()
|
public string GetSelectedUrl()
|
||||||
{
|
{
|
||||||
string serverUrl = Account.Selected!.serverInfo.url;
|
string serverUrl = Account.Selected!.serverInfo.url;
|
||||||
string? streamId = Stream.Selected?.id;
|
string? streamId = Stream.Selected?.id;
|
||||||
string? branchName = Branch.Selected?.name;
|
string? branchName = Branch.Selected?.name;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(streamId)) return serverUrl;
|
if (string.IsNullOrEmpty(streamId))
|
||||||
if (!string.IsNullOrEmpty(branchName)) return $"{serverUrl}/streams/{streamId}/branches/{branchName}";
|
return serverUrl;
|
||||||
|
if (!string.IsNullOrEmpty(branchName))
|
||||||
|
return $"{serverUrl}/streams/{streamId}/branches/{branchName}";
|
||||||
return $"{serverUrl}/streams/{streamId}";
|
return $"{serverUrl}/streams/{streamId}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Awake()
|
public void Awake()
|
||||||
{
|
{
|
||||||
Initialise(true);
|
Initialise(true);
|
||||||
Converter = GetComponent<RecursiveConverter>();
|
Converter = GetComponent<RecursiveConverter>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void Initialise(bool forceRefresh = false)
|
protected void Initialise(bool forceRefresh = false)
|
||||||
{
|
{
|
||||||
CoreUtils.SetupInit();
|
CoreUtils.SetupInit();
|
||||||
|
@ -198,24 +230,24 @@ namespace Speckle.ConnectorUnity.Components
|
||||||
Stream.Initialise();
|
Stream.Initialise();
|
||||||
Branch.Initialise();
|
Branch.Initialise();
|
||||||
Branch.OnSelectionChange = () => OnBranchSelectionChange?.Invoke(Branch.Selected);
|
Branch.OnSelectionChange = () => OnBranchSelectionChange?.Invoke(Branch.Selected);
|
||||||
if(Account.Options is not {Length: > 0} || forceRefresh)
|
if (Account.Options is not { Length: > 0 } || forceRefresh)
|
||||||
Account.RefreshOptions();
|
Account.RefreshOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnDestroy()
|
public void OnDestroy()
|
||||||
{
|
{
|
||||||
CancellationTokenSource?.Cancel();
|
CancellationTokenSource?.Cancel();
|
||||||
CancellationTokenSource?.Dispose();
|
CancellationTokenSource?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnBeforeSerialize()
|
public void OnBeforeSerialize()
|
||||||
{
|
{
|
||||||
//pass
|
//pass
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnAfterDeserialize()
|
public void OnAfterDeserialize()
|
||||||
{
|
{
|
||||||
Initialise();
|
Initialise();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
using Objects.BuiltElements;
|
using Objects.BuiltElements;
|
||||||
using Speckle.Core.Kits;
|
|
||||||
using UnityEditor;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Objects.Converter.Unity
|
namespace Objects.Converter.Unity
|
||||||
|
|
|
@ -137,7 +137,7 @@ namespace Objects.Converter.Unity
|
||||||
}
|
}
|
||||||
|
|
||||||
var nColors = nativeMesh.colors.Skip(indexOffset).Take(vertexTake).ToArray();
|
var nColors = nativeMesh.colors.Skip(indexOffset).Take(vertexTake).ToArray();
|
||||||
;
|
|
||||||
List<int> sColors = new List<int>(nColors.Length);
|
List<int> sColors = new List<int>(nColors.Length);
|
||||||
sColors.AddRange(nColors.Select(c => c.ToIntColor()));
|
sColors.AddRange(nColors.Select(c => c.ToIntColor()));
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,8 @@ namespace Objects.Converter.Unity
|
||||||
}
|
}
|
||||||
|
|
||||||
//Just used as cache key for the default (null) material
|
//Just used as cache key for the default (null) material
|
||||||
private static RenderMaterial defaultMaterialPlaceholder = new() { id = "defaultMaterial" };
|
private static readonly RenderMaterial DefaultMaterialPlaceholder =
|
||||||
|
new() { id = "defaultMaterial" };
|
||||||
|
|
||||||
public virtual Material RenderMaterialToNative(RenderMaterial? renderMaterial)
|
public virtual Material RenderMaterialToNative(RenderMaterial? renderMaterial)
|
||||||
{
|
{
|
||||||
|
@ -57,13 +58,13 @@ namespace Objects.Converter.Unity
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
!LoadedAssets.TryGetObject(
|
!LoadedAssets.TryGetObject(
|
||||||
defaultMaterialPlaceholder,
|
DefaultMaterialPlaceholder,
|
||||||
out Material? defaultMaterial
|
out Material? defaultMaterial
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
defaultMaterial = new Material(OpaqueMaterialShader);
|
defaultMaterial = new Material(OpaqueMaterialShader);
|
||||||
LoadedAssets.TrySaveObject(defaultMaterialPlaceholder, defaultMaterial);
|
LoadedAssets.TrySaveObject(DefaultMaterialPlaceholder, defaultMaterial);
|
||||||
}
|
}
|
||||||
return defaultMaterial;
|
return defaultMaterial;
|
||||||
}
|
}
|
||||||
|
@ -104,9 +105,7 @@ namespace Objects.Converter.Unity
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (shader.name == "Lit") //URP lit
|
else if (shader.name == "Lit") //URP lit
|
||||||
{
|
{ }
|
||||||
ShaderHelpers.SetupMaterialWithBlendMode_URP(mat, true, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadedAssets.TrySaveObject(renderMaterial, mat);
|
LoadedAssets.TrySaveObject(renderMaterial, mat);
|
||||||
|
|
|
@ -1,12 +1,4 @@
|
||||||
using Objects.Geometry;
|
using UnityEngine;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Serialization;
|
|
||||||
using Mesh = Objects.Geometry.Mesh;
|
|
||||||
|
|
||||||
namespace Objects.Converter.Unity
|
namespace Objects.Converter.Unity
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,6 @@ using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Objects.BuiltElements;
|
using Objects.BuiltElements;
|
||||||
using Objects.Organization;
|
|
||||||
using Objects.Other;
|
using Objects.Other;
|
||||||
using Speckle.ConnectorUnity.Utils;
|
using Speckle.ConnectorUnity.Utils;
|
||||||
using Speckle.ConnectorUnity.NativeCache;
|
using Speckle.ConnectorUnity.NativeCache;
|
||||||
|
@ -28,11 +27,11 @@ namespace Objects.Converter.Unity
|
||||||
public string Author => "Speckle";
|
public string Author => "Speckle";
|
||||||
public string WebsiteOrEmail => "https://speckle.systems";
|
public string WebsiteOrEmail => "https://speckle.systems";
|
||||||
|
|
||||||
public ProgressReport Report { get; }
|
public ProgressReport Report => throw new NotImplementedException();
|
||||||
public ReceiveMode ReceiveMode { get; set; }
|
public ReceiveMode ReceiveMode { get; set; }
|
||||||
|
|
||||||
public IEnumerable<string> GetServicedApplications() =>
|
public IEnumerable<string> GetServicedApplications() =>
|
||||||
new string[] { HostApplications.Unity.Name };
|
new[] { HostApplications.Unity.Name };
|
||||||
|
|
||||||
public AbstractNativeCache LoadedAssets { get; private set; }
|
public AbstractNativeCache LoadedAssets { get; private set; }
|
||||||
|
|
||||||
|
@ -238,8 +237,6 @@ namespace Objects.Converter.Unity
|
||||||
// return false;
|
// return false;
|
||||||
case View3D _:
|
case View3D _:
|
||||||
return shouldConvertViews;
|
return shouldConvertViews;
|
||||||
case Model:
|
|
||||||
return false; //This allows us to traverse older commits pre-collections
|
|
||||||
case Collection:
|
case Collection:
|
||||||
return true;
|
return true;
|
||||||
case Mesh:
|
case Mesh:
|
||||||
|
|
|
@ -22,103 +22,117 @@ using UnityEngine;
|
||||||
|
|
||||||
namespace Speckle.ConnectorUnity
|
namespace Speckle.ConnectorUnity
|
||||||
{
|
{
|
||||||
/// Author: Pim de Witte (pimdewitte.com) and contributors, https://github.com/PimDeWitte/UnityMainThreadDispatcher
|
/// Author: Pim de Witte (pimdewitte.com) and contributors, https://github.com/PimDeWitte/UnityMainThreadDispatcher
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A thread-safe class which holds a queue with actions to execute on the next Update() method. It can be used to make calls to the main thread for
|
/// A thread-safe class which holds a queue with actions to execute on the next Update() method. It can be used to make calls to the main thread for
|
||||||
/// things such as UI Manipulation in Unity. It was developed for use in combination with the Firebase Unity plugin, which uses separate threads for event handling
|
/// things such as UI Manipulation in Unity. It was developed for use in combination with the Firebase Unity plugin, which uses separate threads for event handling
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Dispatcher : MonoBehaviour {
|
public class Dispatcher : MonoBehaviour
|
||||||
|
{
|
||||||
|
private static readonly Queue<Action> _executionQueue = new Queue<Action>();
|
||||||
|
|
||||||
private static readonly Queue<Action> _executionQueue = new Queue<Action>();
|
public void Update()
|
||||||
|
{
|
||||||
|
lock (_executionQueue)
|
||||||
|
{
|
||||||
|
while (_executionQueue.Count > 0)
|
||||||
|
{
|
||||||
|
_executionQueue.Dequeue().Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Update() {
|
/// <summary>
|
||||||
lock(_executionQueue) {
|
/// Locks the queue and adds the IEnumerator to the queue
|
||||||
while (_executionQueue.Count > 0) {
|
/// </summary>
|
||||||
_executionQueue.Dequeue().Invoke();
|
/// <param name="action">IEnumerator function that will be executed from the main thread.</param>
|
||||||
}
|
public void Enqueue(IEnumerator action)
|
||||||
}
|
{
|
||||||
}
|
lock (_executionQueue)
|
||||||
|
{
|
||||||
|
_executionQueue.Enqueue(() =>
|
||||||
|
{
|
||||||
|
StartCoroutine(action);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Locks the queue and adds the IEnumerator to the queue
|
/// Locks the queue and adds the Action to the queue
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="action">IEnumerator function that will be executed from the main thread.</param>
|
/// <param name="action">function that will be executed from the main thread.</param>
|
||||||
public void Enqueue(IEnumerator action) {
|
public void Enqueue(Action action)
|
||||||
lock (_executionQueue) {
|
{
|
||||||
_executionQueue.Enqueue (() => {
|
Enqueue(ActionWrapper(action));
|
||||||
StartCoroutine (action);
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Locks the queue and adds the Action to the queue
|
/// Locks the queue and adds the Action to the queue, returning a Task which is completed when the action completes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="action">function that will be executed from the main thread.</param>
|
/// <param name="action">function that will be executed from the main thread.</param>
|
||||||
public void Enqueue(Action action)
|
/// <returns>A Task that can be awaited until the action completes</returns>
|
||||||
{
|
public Task EnqueueAsync(Action action)
|
||||||
Enqueue(ActionWrapper(action));
|
{
|
||||||
}
|
var tcs = new TaskCompletionSource<bool>();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Locks the queue and adds the Action to the queue, returning a Task which is completed when the action completes
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">function that will be executed from the main thread.</param>
|
|
||||||
/// <returns>A Task that can be awaited until the action completes</returns>
|
|
||||||
public Task EnqueueAsync(Action action)
|
|
||||||
{
|
|
||||||
var tcs = new TaskCompletionSource<bool>();
|
|
||||||
|
|
||||||
void WrappedAction() {
|
void WrappedAction()
|
||||||
try
|
{
|
||||||
{
|
try
|
||||||
action();
|
{
|
||||||
tcs.TrySetResult(true);
|
action();
|
||||||
} catch (Exception ex)
|
tcs.TrySetResult(true);
|
||||||
{
|
}
|
||||||
tcs.TrySetException(ex);
|
catch (Exception ex)
|
||||||
}
|
{
|
||||||
}
|
tcs.TrySetException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Enqueue(ActionWrapper(WrappedAction));
|
Enqueue(ActionWrapper(WrappedAction));
|
||||||
return tcs.Task;
|
return tcs.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IEnumerator ActionWrapper(Action a)
|
||||||
IEnumerator ActionWrapper(Action a)
|
{
|
||||||
{
|
a();
|
||||||
a();
|
yield return null;
|
||||||
yield return null;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
private static Dispatcher _instance = null;
|
||||||
|
|
||||||
private static Dispatcher _instance = null;
|
public static bool Exists()
|
||||||
|
{
|
||||||
|
return _instance != null;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool Exists() {
|
public static Dispatcher Instance()
|
||||||
return _instance != null;
|
{
|
||||||
}
|
if (!Exists())
|
||||||
|
{
|
||||||
|
throw new Exception(
|
||||||
|
"Could not find the Dispatcher object. Please ensure you have added a Dispatcher object with this script to your scene."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
public static Dispatcher Instance() {
|
void Awake()
|
||||||
if (!Exists ()) {
|
{
|
||||||
throw new Exception ("Could not find the Dispatcher object. Please ensure you have added a Dispatcher object with this script to your scene.");
|
Setup.Init(
|
||||||
}
|
HostApplications.Unity.GetVersion(CoreUtils.GetHostAppVersion()),
|
||||||
return _instance;
|
HostApplications.Unity.Slug
|
||||||
}
|
);
|
||||||
|
|
||||||
|
if (_instance == null)
|
||||||
|
{
|
||||||
|
_instance = this;
|
||||||
|
DontDestroyOnLoad(this.gameObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Awake() {
|
void OnDestroy()
|
||||||
Setup.Init(HostApplications.Unity.GetVersion(CoreUtils.GetHostAppVersion()), HostApplications.Unity.Slug);
|
{
|
||||||
|
_instance = null;
|
||||||
if (_instance == null) {
|
}
|
||||||
_instance = this;
|
}
|
||||||
DontDestroyOnLoad(this.gameObject);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnDestroy() {
|
|
||||||
_instance = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ using Speckle.Core.Kits;
|
||||||
|
|
||||||
namespace Speckle.ConnectorUnity.Factories
|
namespace Speckle.ConnectorUnity.Factories
|
||||||
{
|
{
|
||||||
|
|
||||||
public static class ConverterFactory
|
public static class ConverterFactory
|
||||||
{
|
{
|
||||||
public static ISpeckleConverter GetDefaultConverter()
|
public static ISpeckleConverter GetDefaultConverter()
|
||||||
|
|
|
@ -14,9 +14,12 @@ namespace Speckle.ConnectorUnity.NativeCache
|
||||||
[ExecuteAlways]
|
[ExecuteAlways]
|
||||||
public abstract class AbstractNativeCache : ScriptableObject
|
public abstract class AbstractNativeCache : ScriptableObject
|
||||||
{
|
{
|
||||||
|
|
||||||
protected bool isWriting = false;
|
protected bool isWriting = false;
|
||||||
public abstract bool TryGetObject<T>(Base speckleObject, [NotNullWhen(true)] out T? nativeObject) where T : Object;
|
public abstract bool TryGetObject<T>(
|
||||||
|
Base speckleObject,
|
||||||
|
[NotNullWhen(true)] out T? nativeObject
|
||||||
|
)
|
||||||
|
where T : Object;
|
||||||
|
|
||||||
public abstract bool TrySaveObject(Base speckleObject, Object nativeObject);
|
public abstract bool TrySaveObject(Base speckleObject, Object nativeObject);
|
||||||
|
|
||||||
|
@ -41,7 +44,6 @@ namespace Speckle.ConnectorUnity.NativeCache
|
||||||
{
|
{
|
||||||
FinishWrite();
|
FinishWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class AssetHelpers
|
public static class AssetHelpers
|
||||||
|
@ -49,12 +51,12 @@ namespace Speckle.ConnectorUnity.NativeCache
|
||||||
public static string? GetAssetFolder(Type nativeType, string path)
|
public static string? GetAssetFolder(Type nativeType, string path)
|
||||||
{
|
{
|
||||||
const string format = "{0}/{1}";
|
const string format = "{0}/{1}";
|
||||||
|
|
||||||
if (nativeType == typeof(Mesh))
|
if (nativeType == typeof(Mesh))
|
||||||
{
|
{
|
||||||
return string.Format(format, path, "Geometry");
|
return string.Format(format, path, "Geometry");
|
||||||
}
|
}
|
||||||
if (nativeType == typeof(Material))
|
if (nativeType == typeof(Material))
|
||||||
{
|
{
|
||||||
return string.Format(format, path, "Materials");
|
return string.Format(format, path, "Materials");
|
||||||
}
|
}
|
||||||
|
@ -64,9 +66,10 @@ namespace Speckle.ConnectorUnity.NativeCache
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly HashSet<char> InvalidChars = Path.GetInvalidFileNameChars()
|
||||||
private static readonly HashSet<char> InvalidChars = Path.GetInvalidFileNameChars().ToHashSet();
|
.ToHashSet();
|
||||||
|
|
||||||
public static string GetAssetName(Base speckleObject, Type nativeType)
|
public static string GetAssetName(Base speckleObject, Type nativeType)
|
||||||
{
|
{
|
||||||
string suffix = GetAssetSuffix(nativeType);
|
string suffix = GetAssetSuffix(nativeType);
|
||||||
|
@ -78,15 +81,18 @@ namespace Speckle.ConnectorUnity.NativeCache
|
||||||
|
|
||||||
public static string GetAssetSuffix(Type nativeType)
|
public static string GetAssetSuffix(Type nativeType)
|
||||||
{
|
{
|
||||||
if (nativeType == typeof(Material)) return ".mat";
|
if (nativeType == typeof(Material))
|
||||||
if (nativeType == typeof(GameObject)) return ".prefab";
|
return ".mat";
|
||||||
|
if (nativeType == typeof(GameObject))
|
||||||
|
return ".prefab";
|
||||||
return ".asset";
|
return ".asset";
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("use " + nameof(CoreUtils.GenerateObjectName))]
|
[Obsolete("use " + nameof(CoreUtils.GenerateObjectName))]
|
||||||
public static string GetObjectName(Base speckleObject)
|
public static string GetObjectName(Base speckleObject)
|
||||||
{
|
{
|
||||||
string objectName = speckleObject["name"] as string ?? speckleObject.speckle_type.Split(':').Last();
|
string objectName =
|
||||||
|
speckleObject["name"] as string ?? speckleObject.speckle_type.Split(':').Last();
|
||||||
return $"{objectName} - {speckleObject.id}";
|
return $"{objectName} - {speckleObject.id}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,14 @@ namespace Speckle.ConnectorUnity.NativeCache
|
||||||
{
|
{
|
||||||
[SerializeField, SerializeReference]
|
[SerializeField, SerializeReference]
|
||||||
public List<AbstractNativeCache> nativeCaches;
|
public List<AbstractNativeCache> nativeCaches;
|
||||||
|
|
||||||
public override bool TryGetObject<T>(Base speckleObject, out T nativeObject) where T : class
|
public override bool TryGetObject<T>(Base speckleObject, out T nativeObject)
|
||||||
|
where T : class
|
||||||
{
|
{
|
||||||
foreach (var c in nativeCaches)
|
foreach (var c in nativeCaches)
|
||||||
{
|
{
|
||||||
if (c.TryGetObject(speckleObject, out nativeObject)) return true;
|
if (c.TryGetObject(speckleObject, out nativeObject))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
nativeObject = null;
|
nativeObject = null;
|
||||||
return false;
|
return false;
|
||||||
|
@ -24,12 +26,13 @@ namespace Speckle.ConnectorUnity.NativeCache
|
||||||
public override bool TrySaveObject(Base speckleObject, Object nativeObject)
|
public override bool TrySaveObject(Base speckleObject, Object nativeObject)
|
||||||
{
|
{
|
||||||
bool hasSavedSomewhere = false;
|
bool hasSavedSomewhere = false;
|
||||||
|
|
||||||
foreach (var c in nativeCaches)
|
foreach (var c in nativeCaches)
|
||||||
{
|
{
|
||||||
hasSavedSomewhere = hasSavedSomewhere || c.TrySaveObject(speckleObject, nativeObject);
|
hasSavedSomewhere =
|
||||||
|
hasSavedSomewhere || c.TrySaveObject(speckleObject, nativeObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasSavedSomewhere;
|
return hasSavedSomewhere;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +60,5 @@ namespace Speckle.ConnectorUnity.NativeCache
|
||||||
}
|
}
|
||||||
base.FinishWrite();
|
base.FinishWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,40 +6,48 @@ using Object = UnityEngine.Object;
|
||||||
|
|
||||||
namespace Speckle.ConnectorUnity.NativeCache
|
namespace Speckle.ConnectorUnity.NativeCache
|
||||||
{
|
{
|
||||||
#nullable enable
|
#nullable enable
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// In memory native object cache
|
/// In memory native object cache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class MemoryNativeCache : AbstractNativeCache
|
public sealed class MemoryNativeCache : AbstractNativeCache
|
||||||
{
|
{
|
||||||
public IDictionary<string, List<Object>> LoadedAssets { get; set; } = new Dictionary<string, List<Object>>();
|
public IDictionary<string, List<Object>> LoadedAssets { get; set; } =
|
||||||
|
new Dictionary<string, List<Object>>();
|
||||||
public override bool TryGetObject<T>(Base speckleObject, [NotNullWhen(true)] out T? nativeObject) where T : class
|
|
||||||
|
public override bool TryGetObject<T>(
|
||||||
|
Base speckleObject,
|
||||||
|
[NotNullWhen(true)] out T? nativeObject
|
||||||
|
)
|
||||||
|
where T : class
|
||||||
{
|
{
|
||||||
if (TryGetObject(speckleObject, out List<Object>? e))
|
if (TryGetObject(speckleObject, out List<Object>? e))
|
||||||
{
|
{
|
||||||
nativeObject = (T?)e.FirstOrDefault(x => x is T);
|
nativeObject = (T?)e.FirstOrDefault(x => x is T);
|
||||||
return nativeObject != null;
|
return nativeObject != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
nativeObject = null;
|
nativeObject = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetObject(Base speckleObject, [NotNullWhen(true)] out List<Object>? nativeObject)
|
public bool TryGetObject(
|
||||||
|
Base speckleObject,
|
||||||
|
[NotNullWhen(true)] out List<Object>? nativeObject
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return LoadedAssets.TryGetValue(speckleObject.id, out nativeObject);
|
return LoadedAssets.TryGetValue(speckleObject.id, out nativeObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool TrySaveObject(Base speckleObject, Object nativeObject)
|
public override bool TrySaveObject(Base speckleObject, Object nativeObject)
|
||||||
{
|
{
|
||||||
if (LoadedAssets.ContainsKey(speckleObject.id))
|
if (LoadedAssets.TryGetValue(speckleObject.id, out List<Object>? assets))
|
||||||
{
|
{
|
||||||
LoadedAssets[speckleObject.id].Add(nativeObject);
|
assets.Add(nativeObject);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadedAssets.Add(speckleObject.id, new List<Object>{nativeObject});
|
LoadedAssets.Add(speckleObject.id, new List<Object> { nativeObject });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ using Object = UnityEngine.Object;
|
||||||
|
|
||||||
namespace Speckle.ConnectorUnity.NativeCache
|
namespace Speckle.ConnectorUnity.NativeCache
|
||||||
{
|
{
|
||||||
#nullable enable
|
#nullable enable
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads existing assets from <see cref="Resources"/>
|
/// Loads existing assets from <see cref="Resources"/>
|
||||||
/// by friendly id (see <see cref="AssetHelpers.GetAssetName"/>)
|
/// by friendly id (see <see cref="AssetHelpers.GetAssetName"/>)
|
||||||
|
@ -14,19 +14,25 @@ namespace Speckle.ConnectorUnity.NativeCache
|
||||||
public sealed class ResourcesNativeCache : AbstractNativeCache
|
public sealed class ResourcesNativeCache : AbstractNativeCache
|
||||||
{
|
{
|
||||||
public bool matchByName = true;
|
public bool matchByName = true;
|
||||||
|
|
||||||
public override bool TryGetObject<T>(Base speckleObject, [NotNullWhen(true)] out T? nativeObject) where T : class
|
public override bool TryGetObject<T>(
|
||||||
|
Base speckleObject,
|
||||||
|
[NotNullWhen(true)] out T? nativeObject
|
||||||
|
)
|
||||||
|
where T : class
|
||||||
{
|
{
|
||||||
if (matchByName)
|
if (matchByName)
|
||||||
{
|
{
|
||||||
string? speckleName = speckleObject["name"] as string ?? speckleObject["Name"] as string;
|
string? speckleName =
|
||||||
|
speckleObject["name"] as string ?? speckleObject["Name"] as string;
|
||||||
if (!string.IsNullOrWhiteSpace(speckleName))
|
if (!string.IsNullOrWhiteSpace(speckleName))
|
||||||
{
|
{
|
||||||
nativeObject = Resources.Load<T>(speckleName);
|
nativeObject = Resources.Load<T>(speckleName);
|
||||||
if (nativeObject != null) return true;
|
if (nativeObject != null)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nativeObject = Resources.Load<T>(AssetHelpers.GetAssetName(speckleObject, typeof(T)));
|
nativeObject = Resources.Load<T>(AssetHelpers.GetAssetName(speckleObject, typeof(T)));
|
||||||
return nativeObject != null;
|
return nativeObject != null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,12 @@ using Speckle.ConnectorUnity.NativeCache.Editor;
|
||||||
|
|
||||||
namespace Speckle.ConnectorUnity
|
namespace Speckle.ConnectorUnity
|
||||||
{
|
{
|
||||||
#nullable enable
|
#nullable enable
|
||||||
public static class NativeCacheFactory
|
public static class NativeCacheFactory
|
||||||
{
|
{
|
||||||
|
public static List<AbstractNativeCache> GetDefaultNativeCacheSetup(
|
||||||
public static List<AbstractNativeCache> GetDefaultNativeCacheSetup(bool generateAssets = false)
|
bool generateAssets = false
|
||||||
|
)
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
if (generateAssets)
|
if (generateAssets)
|
||||||
|
@ -21,7 +22,6 @@ namespace Speckle.ConnectorUnity
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return GetStandaloneCacheSetup();
|
return GetStandaloneCacheSetup();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<AbstractNativeCache> GetStandaloneCacheSetup()
|
public static List<AbstractNativeCache> GetStandaloneCacheSetup()
|
||||||
|
@ -32,7 +32,7 @@ namespace Speckle.ConnectorUnity
|
||||||
ScriptableObject.CreateInstance<MemoryNativeCache>(),
|
ScriptableObject.CreateInstance<MemoryNativeCache>(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
public static List<AbstractNativeCache> GetEditorCacheSetup()
|
public static List<AbstractNativeCache> GetEditorCacheSetup()
|
||||||
{
|
{
|
||||||
|
@ -46,4 +46,3 @@ namespace Speckle.ConnectorUnity
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -196,4 +196,4 @@ namespace System.Collections.Concurrent
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,35 +8,35 @@ using Speckle.Core.Logging;
|
||||||
|
|
||||||
namespace Speckle.ConnectorUnity
|
namespace Speckle.ConnectorUnity
|
||||||
{
|
{
|
||||||
public static class Streams
|
public static class Streams
|
||||||
{
|
|
||||||
public static async Task<List<Stream>> List(int limit = 10)
|
|
||||||
{
|
{
|
||||||
var account = AccountManager.GetDefaultAccount();
|
public static async Task<List<Stream>> List(int limit = 10)
|
||||||
if (account == null)
|
{
|
||||||
return new List<Stream>();
|
var account = AccountManager.GetDefaultAccount();
|
||||||
var client = new Client(account);
|
if (account == null)
|
||||||
|
return new List<Stream>();
|
||||||
|
var client = new Client(account);
|
||||||
|
|
||||||
var res = await client.StreamsGet(limit);
|
var res = await client.StreamsGet(limit);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<Stream> Get(string streamId, int limit = 10)
|
||||||
|
{
|
||||||
|
var account = AccountManager.GetDefaultAccount();
|
||||||
|
if (account == null)
|
||||||
|
return null;
|
||||||
|
var client = new Client(account);
|
||||||
|
|
||||||
|
var res = await client.StreamGet(streamId, limit);
|
||||||
|
|
||||||
|
if (res.branches.items != null)
|
||||||
|
{
|
||||||
|
res.branches.items.Reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public static async Task<Stream> Get(string streamId, int limit = 10)
|
|
||||||
{
|
|
||||||
var account = AccountManager.GetDefaultAccount();
|
|
||||||
if (account == null)
|
|
||||||
return null;
|
|
||||||
var client = new Client(account);
|
|
||||||
|
|
||||||
var res = await client.StreamGet(streamId, limit);
|
|
||||||
|
|
||||||
if (res.branches.items != null)
|
|
||||||
{
|
|
||||||
res.branches.items.Reverse();
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,37 +9,41 @@ namespace Speckle.ConnectorUnity.Utils
|
||||||
{
|
{
|
||||||
public static void SetupInit()
|
public static void SetupInit()
|
||||||
{
|
{
|
||||||
Setup.Init(HostApplications.Unity.GetVersion(GetHostAppVersion()), HostApplications.Unity.Slug);
|
Setup.Init(
|
||||||
|
HostApplications.Unity.GetVersion(GetHostAppVersion()),
|
||||||
|
HostApplications.Unity.Slug
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HostAppVersion GetHostAppVersion()
|
public static HostAppVersion GetHostAppVersion()
|
||||||
{
|
{
|
||||||
#if UNITY_2019
|
#if UNITY_2019
|
||||||
return HostAppVersion.v2019;
|
return HostAppVersion.v2019;
|
||||||
#elif UNITY_2020
|
#elif UNITY_2020
|
||||||
return HostAppVersion.v2020;
|
return HostAppVersion.v2020;
|
||||||
#elif UNITY_2021
|
#elif UNITY_2021
|
||||||
return HostAppVersion.v2021;
|
return HostAppVersion.v2021;
|
||||||
#elif UNITY_2022
|
#elif UNITY_2022
|
||||||
return HostAppVersion.v2022;
|
return HostAppVersion.v2022;
|
||||||
#elif UNITY_2023
|
#elif UNITY_2023
|
||||||
return HostAppVersion.v2023;
|
return HostAppVersion.v2023;
|
||||||
#elif UNITY_2024
|
#elif UNITY_2024
|
||||||
return HostAppVersion.v2024;
|
return HostAppVersion.v2024;
|
||||||
#elif UNITY_2025
|
#elif UNITY_2025
|
||||||
return HostAppVersion.v2025;
|
return HostAppVersion.v2025;
|
||||||
#else
|
#else
|
||||||
return HostAppVersion.v;
|
return HostAppVersion.v;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public const string ObjectNameSeparator = " -- ";
|
public const string ObjectNameSeparator = " -- ";
|
||||||
|
|
||||||
/// <param name="speckleObject">The object to be named</param>
|
/// <param name="speckleObject">The object to be named</param>
|
||||||
/// <returns>A human-readable Object name unique to the given <paramref name="speckleObject"/></returns>
|
/// <returns>A human-readable Object name unique to the given <paramref name="speckleObject"/></returns>
|
||||||
public static string GenerateObjectName(Base speckleObject)
|
public static string GenerateObjectName(Base speckleObject)
|
||||||
{
|
{
|
||||||
var prefix = GetFriendlyObjectName(speckleObject) ?? SimplifiedSpeckleType(speckleObject);
|
var prefix =
|
||||||
|
GetFriendlyObjectName(speckleObject) ?? SimplifiedSpeckleType(speckleObject);
|
||||||
return $"{prefix}{ObjectNameSeparator}{speckleObject.id}";
|
return $"{prefix}{ObjectNameSeparator}{speckleObject.id}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,13 +53,12 @@ namespace Speckle.ConnectorUnity.Utils
|
||||||
?? speckleObject["Name"] as string
|
?? speckleObject["Name"] as string
|
||||||
?? speckleObject["family"] as string;
|
?? speckleObject["family"] as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <param name="speckleObject"></param>
|
/// <param name="speckleObject"></param>
|
||||||
/// <returns>The most significant type in a given <see cref="Base.speckle_type"/></returns>
|
/// <returns>The most significant type in a given <see cref="Base.speckle_type"/></returns>
|
||||||
public static string SimplifiedSpeckleType(Base speckleObject)
|
public static string SimplifiedSpeckleType(Base speckleObject)
|
||||||
{
|
{
|
||||||
return speckleObject.speckle_type.Split(':')[^1];
|
return speckleObject.speckle_type.Split(':')[^1];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,13 @@ namespace Speckle.ConnectorUnity.Utils
|
||||||
/// <param name="propertyName"></param>
|
/// <param name="propertyName"></param>
|
||||||
/// <param name="value"></param>
|
/// <param name="value"></param>
|
||||||
#pragma warning disable CS0618
|
#pragma warning disable CS0618
|
||||||
public static void SetDetachedPropertyChecked(this Base speckleObject, string propertyName, object? value)
|
public static void SetDetachedPropertyChecked(
|
||||||
|
this Base speckleObject,
|
||||||
|
string propertyName,
|
||||||
|
object? value
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if(speckleObject.GetInstanceMembersNames().Any(name => name == propertyName))
|
if (speckleObject.GetInstanceMembersNames().Any(name => name == propertyName))
|
||||||
speckleObject[propertyName] = value;
|
speckleObject[propertyName] = value;
|
||||||
else
|
else
|
||||||
speckleObject[$"@{propertyName}"] = value;
|
speckleObject[$"@{propertyName}"] = value;
|
||||||
|
|
|
@ -107,15 +107,6 @@ namespace Speckle.ConnectorUnity.Utils
|
||||||
material.renderQueue = defaultRenderQueue;
|
material.renderQueue = defaultRenderQueue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetupMaterialWithBlendMode_URP(
|
|
||||||
Material material,
|
|
||||||
bool transparent,
|
|
||||||
int blendMode
|
|
||||||
)
|
|
||||||
{
|
|
||||||
material.SetFloat("__surface", 1);
|
|
||||||
material.SetFloat("__blend", blendMode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ using System.Collections;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Networking;
|
using UnityEngine.Networking;
|
||||||
using UnityEngine.Rendering;
|
|
||||||
|
|
||||||
namespace Speckle.ConnectorUnity.Utils
|
namespace Speckle.ConnectorUnity.Utils
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,31 +17,33 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Account? account = Selected;
|
Account? account = Selected;
|
||||||
if (account == null) return client = null;
|
if (account == null)
|
||||||
if (client == null || !client.Account.Equals(account)) return client = new Client(account);
|
return client = null;
|
||||||
|
if (client == null || !client.Account.Equals(account))
|
||||||
|
return client = new Client(account);
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string? KeyFunction(Account? value) => value?.id;
|
protected override string? KeyFunction(Account? value) => value?.id;
|
||||||
|
|
||||||
public override void RefreshOptions()
|
public override void RefreshOptions()
|
||||||
{
|
{
|
||||||
Account[] accounts;
|
Account[] accounts;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
accounts = AccountManager.GetAccounts().ToArray();
|
accounts = AccountManager.GetAccounts().ToArray();
|
||||||
if(accounts.Length == 0)
|
if (accounts.Length == 0)
|
||||||
Debug.LogWarning("No Accounts found, please login in Manager");
|
Debug.LogWarning("No Accounts found, please login in Manager");
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
accounts = Array.Empty<Account>();
|
accounts = Array.Empty<Account>();
|
||||||
Debug.LogWarning($"Unable to refresh {this}\n{e}");
|
Debug.LogWarning($"Unable to refresh {this}\n{e}");
|
||||||
}
|
}
|
||||||
GenerateOptions(accounts, isDefault: (a, i) => a.isDefault || i == 0);
|
GenerateOptions(accounts, isDefault: (a, i) => a.isDefault || i == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
client?.Dispose();
|
client?.Dispose();
|
||||||
|
|
|
@ -9,38 +9,43 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public sealed class BranchSelection : OptionSelection<Branch>
|
public sealed class BranchSelection : OptionSelection<Branch>
|
||||||
{
|
{
|
||||||
[field: SerializeField, Range(1,100), Tooltip("Number of branches to request")]
|
[field: SerializeField, Range(1, 100), Tooltip("Number of branches to request")]
|
||||||
public int BranchesLimit { get; set; } = 100;
|
public int BranchesLimit { get; set; } = 100;
|
||||||
[field: SerializeField, Range(1,100), Tooltip("Number of commits to request")]
|
|
||||||
|
[field: SerializeField, Range(1, 100), Tooltip("Number of commits to request")]
|
||||||
public int CommitsLimit { get; set; } = 25;
|
public int CommitsLimit { get; set; } = 25;
|
||||||
|
|
||||||
[field: SerializeReference]
|
[field: SerializeReference]
|
||||||
public StreamSelection StreamSelection { get; private set; }
|
public StreamSelection StreamSelection { get; private set; }
|
||||||
public override Client? Client => StreamSelection.Client;
|
public override Client? Client => StreamSelection.Client;
|
||||||
|
|
||||||
public BranchSelection(StreamSelection streamSelection)
|
public BranchSelection(StreamSelection streamSelection)
|
||||||
{
|
{
|
||||||
StreamSelection = streamSelection;
|
StreamSelection = streamSelection;
|
||||||
Initialise();
|
Initialise();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialise()
|
public void Initialise()
|
||||||
{
|
{
|
||||||
StreamSelection.OnSelectionChange = RefreshOptions;
|
StreamSelection.OnSelectionChange = RefreshOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string? KeyFunction(Branch? value) => value?.name;
|
protected override string? KeyFunction(Branch? value) => value?.name;
|
||||||
|
|
||||||
public override void RefreshOptions()
|
public override void RefreshOptions()
|
||||||
{
|
{
|
||||||
Stream? stream = StreamSelection.Selected;
|
Stream? stream = StreamSelection.Selected;
|
||||||
if (stream == null) return;
|
if (stream == null)
|
||||||
|
return;
|
||||||
IList<Branch> branches;
|
IList<Branch> branches;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
branches = Client!.StreamGetBranches(stream.id, BranchesLimit, CommitsLimit).GetAwaiter().GetResult();
|
branches = Client!
|
||||||
|
.StreamGetBranches(stream.id, BranchesLimit, CommitsLimit)
|
||||||
|
.GetAwaiter()
|
||||||
|
.GetResult();
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"Unable to refresh {this}\n{e}");
|
Debug.LogWarning($"Unable to refresh {this}\n{e}");
|
||||||
branches = Array.Empty<Branch>();
|
branches = Array.Empty<Branch>();
|
||||||
|
|
|
@ -6,35 +6,32 @@ using UnityEngine;
|
||||||
#nullable enable
|
#nullable enable
|
||||||
namespace Speckle.ConnectorUnity.Wrappers.Selection
|
namespace Speckle.ConnectorUnity.Wrappers.Selection
|
||||||
{
|
{
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public sealed class CommitSelection : OptionSelection<Commit>
|
public sealed class CommitSelection : OptionSelection<Commit>
|
||||||
{
|
{
|
||||||
|
|
||||||
[field: SerializeReference]
|
[field: SerializeReference]
|
||||||
public BranchSelection BranchSelection { get; private set; }
|
public BranchSelection BranchSelection { get; private set; }
|
||||||
|
|
||||||
public override Client? Client => BranchSelection.Client;
|
public override Client? Client => BranchSelection.Client;
|
||||||
|
|
||||||
public CommitSelection(BranchSelection branchSelection)
|
public CommitSelection(BranchSelection branchSelection)
|
||||||
{
|
{
|
||||||
BranchSelection = branchSelection;
|
BranchSelection = branchSelection;
|
||||||
Initialise();
|
Initialise();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialise()
|
public void Initialise()
|
||||||
{
|
{
|
||||||
BranchSelection.OnSelectionChange = RefreshOptions;
|
BranchSelection.OnSelectionChange = RefreshOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override string? KeyFunction(Commit? value) => value?.id;
|
protected override string? KeyFunction(Commit? value) => value?.id;
|
||||||
|
|
||||||
public override void RefreshOptions()
|
public override void RefreshOptions()
|
||||||
{
|
{
|
||||||
Branch? branch = BranchSelection!.Selected;
|
Branch? branch = BranchSelection!.Selected;
|
||||||
if (branch == null) return;
|
if (branch == null)
|
||||||
|
return;
|
||||||
List<Commit> commits = branch.commits.items;
|
List<Commit> commits = branch.commits.items;
|
||||||
GenerateOptions(commits, (_, i) => i == 0);
|
GenerateOptions(commits, (_, i) => i == 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,8 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection
|
||||||
public abstract class OptionSelection<TOption>
|
public abstract class OptionSelection<TOption>
|
||||||
where TOption : class
|
where TOption : class
|
||||||
{
|
{
|
||||||
[SerializeField] private int selectedIndex = -1;
|
[SerializeField]
|
||||||
|
private int selectedIndex = -1;
|
||||||
|
|
||||||
public int SelectedIndex
|
public int SelectedIndex
|
||||||
{
|
{
|
||||||
|
@ -34,8 +35,10 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (Options is null) return null;
|
if (Options is null)
|
||||||
if (SelectedIndex < 0 || SelectedIndex >= Options.Length) return null;
|
return null;
|
||||||
|
if (SelectedIndex < 0 || SelectedIndex >= Options.Length)
|
||||||
|
return null;
|
||||||
return Options[SelectedIndex];
|
return Options[SelectedIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,22 +55,28 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection
|
||||||
|
|
||||||
protected void GenerateOptions(IList<TOption> source, Func<TOption, int, bool> isDefault)
|
protected void GenerateOptions(IList<TOption> source, Func<TOption, int, bool> isDefault)
|
||||||
{
|
{
|
||||||
List<TOption> optionsToAdd = new (source.Count);
|
List<TOption> optionsToAdd = new(source.Count);
|
||||||
int defaultOption = -1;
|
int defaultOption = -1;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
foreach (TOption? a in source)
|
foreach (TOption? a in source)
|
||||||
{
|
{
|
||||||
if (a == null) continue;
|
if (a == null)
|
||||||
|
continue;
|
||||||
optionsToAdd.Add(a);
|
optionsToAdd.Add(a);
|
||||||
if (isDefault(a, index)) defaultOption = index;
|
if (isDefault(a, index))
|
||||||
|
defaultOption = index;
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOption? currentSelected = Selected;
|
TOption? currentSelected = Selected;
|
||||||
bool selectionOutOfRange = SelectedIndex < 0 || SelectedIndex >= optionsToAdd.Count;
|
bool selectionOutOfRange = SelectedIndex < 0 || SelectedIndex >= optionsToAdd.Count;
|
||||||
if (selectionOutOfRange
|
if (
|
||||||
|| (currentSelected != null
|
selectionOutOfRange
|
||||||
&& KeyFunction(currentSelected) != KeyFunction(optionsToAdd[SelectedIndex])))
|
|| (
|
||||||
|
currentSelected != null
|
||||||
|
&& KeyFunction(currentSelected) != KeyFunction(optionsToAdd[SelectedIndex])
|
||||||
|
)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
selectedIndex = defaultOption;
|
selectedIndex = defaultOption;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,16 +10,19 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection
|
||||||
public sealed class StreamSelection : OptionSelection<Stream>
|
public sealed class StreamSelection : OptionSelection<Stream>
|
||||||
{
|
{
|
||||||
private const int DEFAULT_REQUEST_LIMIT = 50;
|
private const int DEFAULT_REQUEST_LIMIT = 50;
|
||||||
[field: SerializeField, Range(1,100), Tooltip("Number of streams to request")]
|
|
||||||
|
[field: SerializeField, Range(1, 100), Tooltip("Number of streams to request")]
|
||||||
public int StreamsLimit { get; set; } = DEFAULT_REQUEST_LIMIT;
|
public int StreamsLimit { get; set; } = DEFAULT_REQUEST_LIMIT;
|
||||||
|
|
||||||
[field: SerializeReference]
|
[field: SerializeReference]
|
||||||
public AccountSelection AccountSelection { get; private set; }
|
public AccountSelection AccountSelection { get; private set; }
|
||||||
|
|
||||||
public StreamSelection(AccountSelection accountSelection)
|
public StreamSelection(AccountSelection accountSelection)
|
||||||
{
|
{
|
||||||
AccountSelection = accountSelection;
|
AccountSelection = accountSelection;
|
||||||
Initialise();
|
Initialise();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialise()
|
public void Initialise()
|
||||||
{
|
{
|
||||||
AccountSelection.OnSelectionChange = RefreshOptions;
|
AccountSelection.OnSelectionChange = RefreshOptions;
|
||||||
|
@ -28,15 +31,17 @@ namespace Speckle.ConnectorUnity.Wrappers.Selection
|
||||||
public override Client? Client => AccountSelection.Client;
|
public override Client? Client => AccountSelection.Client;
|
||||||
|
|
||||||
protected override string? KeyFunction(Stream? value) => value?.id;
|
protected override string? KeyFunction(Stream? value) => value?.id;
|
||||||
|
|
||||||
public override void RefreshOptions()
|
public override void RefreshOptions()
|
||||||
{
|
{
|
||||||
if (Client == null) return;
|
if (Client == null)
|
||||||
|
return;
|
||||||
IList<Stream> streams;
|
IList<Stream> streams;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
streams = Client.StreamsGet(StreamsLimit).GetAwaiter().GetResult();
|
streams = Client.StreamsGet(StreamsLimit).GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"Unable to refresh {this}\n{e}");
|
Debug.LogWarning($"Unable to refresh {this}\n{e}");
|
||||||
streams = Array.Empty<Stream>();
|
streams = Array.Empty<Stream>();
|
||||||
|
|
|
@ -17,21 +17,20 @@ namespace Speckle.ConnectorUnity.Wrappers
|
||||||
[Serializable, DisallowMultipleComponent]
|
[Serializable, DisallowMultipleComponent]
|
||||||
public class SpeckleProperties : MonoBehaviour, ISerializationCallbackReceiver
|
public class SpeckleProperties : MonoBehaviour, ISerializationCallbackReceiver
|
||||||
{
|
{
|
||||||
|
|
||||||
[SerializeField, HideInInspector]
|
[SerializeField, HideInInspector]
|
||||||
private string _serializedData = "";
|
private string _serializedData = "";
|
||||||
|
|
||||||
[SerializeField, HideInInspector]
|
[SerializeField, HideInInspector]
|
||||||
private bool _hasChanged;
|
private bool _hasChanged;
|
||||||
|
|
||||||
private ObservableConcurrentDictionary<string, object> _data;
|
private ObservableConcurrentDictionary<string, object> _data;
|
||||||
|
|
||||||
public IDictionary<string, object> Data
|
public IDictionary<string, object> Data
|
||||||
{
|
{
|
||||||
get => _data;
|
get => _data;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
((ICollection<KeyValuePair<string, object>>) _data).Clear();
|
((ICollection<KeyValuePair<string, object>>)_data).Clear();
|
||||||
|
|
||||||
foreach (var kvp in value)
|
foreach (var kvp in value)
|
||||||
{
|
{
|
||||||
|
@ -43,18 +42,17 @@ namespace Speckle.ConnectorUnity.Wrappers
|
||||||
[SerializeField, HideInInspector]
|
[SerializeField, HideInInspector]
|
||||||
private string _serializedSpeckleType;
|
private string _serializedSpeckleType;
|
||||||
private Type _speckleType = typeof(Base);
|
private Type _speckleType = typeof(Base);
|
||||||
public Type SpeckleType {
|
public Type SpeckleType
|
||||||
|
{
|
||||||
get => _speckleType ??= typeof(Base);
|
get => _speckleType ??= typeof(Base);
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
|
||||||
Debug.Assert(typeof(Base).IsAssignableFrom(value));
|
Debug.Assert(typeof(Base).IsAssignableFrom(value));
|
||||||
Debug.Assert(!value.IsAbstract);
|
Debug.Assert(!value.IsAbstract);
|
||||||
|
|
||||||
_speckleType = value;
|
_speckleType = value;
|
||||||
_hasChanged = true;
|
_hasChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpeckleProperties()
|
public SpeckleProperties()
|
||||||
|
@ -64,7 +62,7 @@ namespace Speckle.ConnectorUnity.Wrappers
|
||||||
_hasChanged = true;
|
_hasChanged = true;
|
||||||
SpeckleType = typeof(Base);
|
SpeckleType = typeof(Base);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CollectionChangeHandler(object sender, NotifyCollectionChangedEventArgs e)
|
private void CollectionChangeHandler(object sender, NotifyCollectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
_hasChanged = true;
|
_hasChanged = true;
|
||||||
|
@ -72,21 +70,22 @@ namespace Speckle.ConnectorUnity.Wrappers
|
||||||
|
|
||||||
public void OnBeforeSerialize()
|
public void OnBeforeSerialize()
|
||||||
{
|
{
|
||||||
if (!_hasChanged) return;
|
if (!_hasChanged)
|
||||||
|
return;
|
||||||
|
|
||||||
_serializedData = Operations.Serialize(new SpeckleData(Data));
|
_serializedData = Operations.Serialize(new SpeckleData(Data));
|
||||||
_hasChanged = false;
|
_hasChanged = false;
|
||||||
_serializedSpeckleType = SpeckleType.AssemblyQualifiedName;
|
_serializedSpeckleType = SpeckleType.AssemblyQualifiedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnAfterDeserialize()
|
public void OnAfterDeserialize()
|
||||||
{
|
{
|
||||||
var deserializer = new BaseObjectDeserializerV2();
|
var deserializer = new BaseObjectDeserializerV2();
|
||||||
Base speckleData = deserializer.Deserialize(_serializedData);
|
Base speckleData = deserializer.Deserialize(_serializedData);
|
||||||
|
|
||||||
Data = speckleData.GetMembers();
|
Data = speckleData.GetMembers();
|
||||||
_hasChanged = false;
|
_hasChanged = false;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_speckleType = Type.GetType(_serializedSpeckleType);
|
_speckleType = Type.GetType(_serializedSpeckleType);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче