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