feat(converter): Added native asset cache to converter to allow for loading/saving assets in an abstract way
This commit is contained in:
Родитель
837794f6e9
Коммит
abe721a323
|
@ -2064,6 +2064,19 @@ Transform:
|
|||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 6
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &916416845
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 141ce93d2d159c0448b5b8b33b1c0679, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
path: Assets/Resources
|
||||
--- !u!1 &1031574851
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -2848,6 +2861,21 @@ MonoBehaviour:
|
|||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_IsOn: 1
|
||||
--- !u!114 &1409739885
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 88d6b4f2f80eaa14f9f07505f7e44ec2, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
nativeCaches:
|
||||
- {fileID: 916416845}
|
||||
- {fileID: 1951948666}
|
||||
--- !u!1 &1464556211
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -3844,6 +3872,18 @@ CanvasRenderer:
|
|||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1903798475}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &1951948666
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: b3354e8208862c341940152f5340d41a, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!1 &2014586909
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -4034,7 +4074,7 @@ GameObject:
|
|||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2060322467}
|
||||
- component: {fileID: 2060322466}
|
||||
- component: {fileID: 2060322469}
|
||||
- component: {fileID: 2060322468}
|
||||
m_Layer: 0
|
||||
m_Name: EditorReceiver
|
||||
|
@ -4043,24 +4083,6 @@ GameObject:
|
|||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &2060322466
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2060322465}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 730f6d2eecf16994c918395debc877e7, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
SelectedAccountIndex: 0
|
||||
SelectedStreamIndex: 0
|
||||
SelectedBranchIndex: 0
|
||||
SelectedCommitIndex: 0
|
||||
OldSelectedAccountIndex: 0
|
||||
OldSelectedStreamIndex: 0
|
||||
--- !u!4 &2060322467
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -4077,6 +4099,24 @@ Transform:
|
|||
m_RootOrder: 9
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &2060322468
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2060322465}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 730f6d2eecf16994c918395debc877e7, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
SelectedAccountIndex: 0
|
||||
SelectedStreamIndex: 15
|
||||
SelectedBranchIndex: 0
|
||||
SelectedCommitIndex: 0
|
||||
OldSelectedAccountIndex: 0
|
||||
OldSelectedStreamIndex: 15
|
||||
--- !u!114 &2060322469
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
|
@ -4088,6 +4128,7 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: ed6cbf9ce4dca0349997d163ec9bce7e, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
<AssetCache>k__BackingField: {fileID: 1409739885}
|
||||
--- !u!1 &2066864134
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"com.unity.2d.sprite": "1.0.0",
|
||||
"com.unity.collab-proxy": "1.17.0",
|
||||
"com.unity.collab-proxy": "1.17.2",
|
||||
"com.unity.ide.rider": "3.0.15",
|
||||
"com.unity.ide.visualstudio": "2.0.16",
|
||||
"com.unity.ide.vscode": "1.2.5",
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"dependencies": {}
|
||||
},
|
||||
"com.unity.collab-proxy": {
|
||||
"version": "1.17.0",
|
||||
"version": "1.17.2",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
|
@ -55,7 +55,7 @@
|
|||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.services.core": {
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.2",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
|
|
|
@ -10,6 +10,7 @@ using Speckle.Core.Logging;
|
|||
using Speckle.Core.Models;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
using SMesh = Objects.Geometry.Mesh;
|
||||
using Transform = UnityEngine.Transform;
|
||||
using STransform = Objects.Other.Transform;
|
||||
|
@ -216,29 +217,21 @@ namespace Objects.Converter.Unity
|
|||
return null;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Check `Resources` for existing cached prefab asset
|
||||
// TODO: this isn't how we check for existing materials, maybe there's a reason not to call LoadAssetPath constantly
|
||||
string assetName = $"{GetAssetName(block.blockDefinition)}.prefab"
|
||||
.Trim(Path.GetInvalidFileNameChars());
|
||||
const string assetPath = "Assets/Resources/Prefabs/";
|
||||
if (StreamManager.GenerateAssets) //TODO: I don't like how the converter is aware of StreamManager
|
||||
// Check for existing conversions
|
||||
if(LoadedAssets.TryGetObject(block.blockDefinition, out GameObject? existingPrefab))
|
||||
{
|
||||
GameObject? existing = AssetDatabase.LoadAssetAtPath<GameObject>($"{assetPath}/{assetName}");
|
||||
if (existing)
|
||||
{
|
||||
var go = (GameObject) PrefabUtility.InstantiatePrefab(existing);
|
||||
go.name = block.blockDefinition.name ?? "";
|
||||
return go;
|
||||
}
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
var go = (GameObject) PrefabUtility.InstantiatePrefab(existingPrefab);
|
||||
#else
|
||||
var go = Object.Instantiate(existingPrefab);
|
||||
#endif
|
||||
|
||||
// No existing found, so we Convert the block
|
||||
|
||||
GameObject native = new GameObject(block.blockDefinition.name ?? "");
|
||||
TransformToNativeTransform(native.transform, block.transform);
|
||||
go.name = block.blockDefinition.name ?? "";
|
||||
return go;
|
||||
}
|
||||
|
||||
// Convert the block definition
|
||||
GameObject native = new GameObject(block.blockDefinition.name ?? "");
|
||||
|
||||
List<SMesh> meshes = new();
|
||||
List<Base> others = new();
|
||||
foreach (Base geo in block.blockDefinition.geometry)
|
||||
|
@ -262,14 +255,9 @@ namespace Objects.Converter.Unity
|
|||
c.transform.SetParent(native.transform, false);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (StreamManager.GenerateAssets) //TODO: I don't like how the converter is aware of StreamManager
|
||||
{
|
||||
CreateDirectoryFromAssetPath(assetPath);
|
||||
PrefabUtility.SaveAsPrefabAssetAndConnect(native, $"Assets/Resources/Prefabs/{assetName}",
|
||||
InteractionMode.AutomatedAction);
|
||||
}
|
||||
#endif
|
||||
LoadedAssets.TrySaveObject(block.blockDefinition, native);
|
||||
|
||||
TransformToNativeTransform(native.transform, block.transform);
|
||||
|
||||
return native;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ using Objects.Other;
|
|||
using Objects.Utils;
|
||||
using PlasticPipe.Certificates;
|
||||
using Speckle.ConnectorUnity;
|
||||
using Speckle.ConnectorUnity.NativeCache;
|
||||
using Speckle.Core.Models;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
@ -207,7 +208,7 @@ namespace Objects.Converter.Unity
|
|||
/// <summary>
|
||||
/// Converts multiple <paramref name="meshes"/> (e.g. with different materials) into one native mesh
|
||||
/// </summary>
|
||||
/// <param name="element">Root element who's name/id is used to identify the mesh</param>
|
||||
/// <param name="element">The <see cref="Base"/> object being converted</param>
|
||||
/// <param name="meshes">Collection of <see cref="Objects.Geometry.Mesh"/>es that shall be converted</param>
|
||||
/// <returns>A <see cref="GameObject"/> with the converted <see cref="UnityEngine.Mesh"/>, <see cref="MeshFilter"/>, and <see cref="MeshRenderer"/></returns>
|
||||
public GameObject? MeshesToNative(Base element, IReadOnlyCollection<SMesh> meshes)
|
||||
|
@ -222,10 +223,10 @@ namespace Objects.Converter.Unity
|
|||
Material[] nativeMaterials = RenderMaterialsToNative(meshes);
|
||||
Vector3 center;
|
||||
|
||||
if (LoadedAssets.TryGetValue(element.id, out var existingObj)
|
||||
&& existingObj is Mesh existing)
|
||||
if (LoadedAssets.TryGetObject(element, out Mesh? existing))
|
||||
{
|
||||
nativeMesh = existing;
|
||||
//todo This is pretty inefficient, having to the mesh data anyway just to get the center... eek
|
||||
MeshDataToNative(meshes,
|
||||
out List<Vector3> verts,
|
||||
out _,
|
||||
|
@ -236,22 +237,15 @@ namespace Objects.Converter.Unity
|
|||
else
|
||||
{
|
||||
MeshToNativeMesh(meshes, out nativeMesh, out center);
|
||||
string name = GetAssetName(element);
|
||||
string name = AssetHelpers.GetObjectName(element);
|
||||
nativeMesh.name = name;
|
||||
#if UNITY_EDITOR
|
||||
if (StreamManager.GenerateAssets) //TODO: I don't like how the converter is aware of StreamManager
|
||||
{
|
||||
const string assetPath = "Assets/Resources/Meshes/Speckle Generated/";
|
||||
CreateDirectoryFromAssetPath(assetPath);
|
||||
AssetDatabase.CreateAsset(nativeMesh, $"{assetPath}/{name}");
|
||||
}
|
||||
#endif
|
||||
LoadedAssets.TrySaveObject(element, nativeMesh);
|
||||
}
|
||||
|
||||
var go = new GameObject();
|
||||
go.transform.position = center;
|
||||
go.SafeMeshSet(nativeMesh, nativeMaterials);
|
||||
|
||||
|
||||
return go;
|
||||
}
|
||||
|
||||
|
@ -461,19 +455,14 @@ namespace Objects.Converter.Unity
|
|||
//todo support more complex materials
|
||||
var shader = Shader.Find("Standard");
|
||||
Material mat = new Material(shader);
|
||||
|
||||
//if a renderMaterial is passed use that, otherwise try get it from the mesh itself
|
||||
|
||||
// 1. If no renderMaterial was passed, use default material
|
||||
if (renderMaterial == null) return mat;
|
||||
|
||||
// 1. match material by name, if any
|
||||
string materialName = string.IsNullOrWhiteSpace(renderMaterial.name)
|
||||
? $"material-{renderMaterial.id}"
|
||||
: renderMaterial.name.Replace('/', '-');
|
||||
|
||||
if (LoadedAssets.TryGetValue(materialName, out Object asset)
|
||||
&& asset is Material loadedMaterial) return loadedMaterial;
|
||||
|
||||
// 2. re-create material by setting diffuse color and transparency on standard shaders
|
||||
// 2. Try get existing/override material from asset cache
|
||||
if (LoadedAssets.TryGetObject(renderMaterial, out Material? loadedMaterial)) return loadedMaterial;
|
||||
|
||||
// 3. Otherwise, convert fresh!
|
||||
if (renderMaterial.opacity < 1)
|
||||
{
|
||||
shader = Shader.Find("Transparent/Diffuse");
|
||||
|
@ -482,51 +471,19 @@ namespace Objects.Converter.Unity
|
|||
|
||||
var c = renderMaterial.diffuse.ToUnityColor();
|
||||
mat.color = new Color(c.r, c.g, c.b, (float) renderMaterial.opacity);
|
||||
mat.name = materialName;
|
||||
mat.name = AssetHelpers.GetObjectName(renderMaterial);;
|
||||
mat.SetFloat(Metallic, (float) renderMaterial.metalness);
|
||||
mat.SetFloat(Glossiness, 1 - (float) renderMaterial.roughness);
|
||||
|
||||
if (renderMaterial.emissive != SColor.Black.ToArgb()) mat.EnableKeyword("_EMISSION");
|
||||
mat.SetColor(EmissionColor, renderMaterial.emissive.ToUnityColor());
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (StreamManager.GenerateAssets) //TODO: I don't like how the converter is aware of StreamManager
|
||||
{
|
||||
var invalidChars = Path.GetInvalidFileNameChars();
|
||||
string name = new(mat.name.Where(x => !invalidChars.Contains(x)).ToArray());
|
||||
|
||||
const string assetPath = "Assets/Resources/Materials/Speckle Generated/";
|
||||
CreateDirectoryFromAssetPath(assetPath);
|
||||
|
||||
if (AssetDatabase.LoadAllAssetsAtPath($"{assetPath}/{name}.mat")
|
||||
.Length == 0)
|
||||
AssetDatabase.CreateAsset(mat, $"{assetPath}/{name}.mat");
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
LoadedAssets.TrySaveObject(renderMaterial, mat);
|
||||
|
||||
return mat;
|
||||
// 3. if not renderMaterial was passed, the default shader will be used
|
||||
}
|
||||
|
||||
protected static string GetAssetName(Base b, bool alwaysIncludeId = true)
|
||||
{
|
||||
var invalidChars = Path.GetInvalidFileNameChars();
|
||||
string id = b.id;
|
||||
foreach (var nameAlias in new[] {"name", "Name"})
|
||||
{
|
||||
string? rawName = b[nameAlias] as string;
|
||||
if (string.IsNullOrWhiteSpace(rawName)) continue;
|
||||
|
||||
string name = new(rawName.Where(x => !invalidChars.Contains(x)).ToArray());
|
||||
|
||||
return alwaysIncludeId ? $"{name} - {id}" : name;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@ using System.Collections;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Objects.BuiltElements;
|
||||
using Objects.Other;
|
||||
using Speckle.ConnectorUnity;
|
||||
using Speckle.ConnectorUnity.NativeCache;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Mesh = Objects.Geometry.Mesh;
|
||||
|
@ -32,14 +32,14 @@ namespace Objects.Converter.Unity
|
|||
|
||||
public IEnumerable<string> GetServicedApplications() => new string[] {VersionedHostApplications.Unity};
|
||||
|
||||
public Dictionary<string, Object> LoadedAssets { get; private set; }
|
||||
public AbstractNativeCache LoadedAssets { get; private set; }
|
||||
|
||||
public void SetContextDocument(object doc)
|
||||
{
|
||||
if (doc is not Dictionary<string, Object> loadedAssets)
|
||||
if (doc is not AbstractNativeCache context)
|
||||
throw new ArgumentException(
|
||||
$"Expected {nameof(doc)} to be of type {typeof(Dictionary<string, Object>)}", nameof(doc));
|
||||
LoadedAssets = loadedAssets;
|
||||
LoadedAssets = context;
|
||||
}
|
||||
|
||||
public void SetContextObjects(List<ApplicationObject> objects) => throw new NotImplementedException();
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
"name": "Speckle.Connector.Editor",
|
||||
"rootNamespace": "Speckle.ConnectorUnity",
|
||||
"references": [
|
||||
"GUID:eed1b8b83e2c0074d9e5de2348e3ff72"
|
||||
"GUID:eed1b8b83e2c0074d9e5de2348e3ff72",
|
||||
"GUID:05078f9b6da40444fbd72ec600449925"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Sentry;
|
||||
using Speckle.ConnectorUnity.NativeCache;
|
||||
using Speckle.Core.Api;
|
||||
using Speckle.Core.Credentials;
|
||||
using Speckle.Core.Kits;
|
||||
|
@ -14,336 +15,353 @@ using UnityEngine;
|
|||
|
||||
namespace Speckle.ConnectorUnity.Editor
|
||||
{
|
||||
[CustomEditor(typeof(StreamManager))]
|
||||
[CanEditMultipleObjects]
|
||||
public class StreamManagerEditor : UnityEditor.Editor
|
||||
{
|
||||
private bool _foldOutAccount;
|
||||
private int _totalChildrenCount = 0;
|
||||
private StreamManager _streamManager;
|
||||
|
||||
public int StreamsLimit { get; set; } = 30;
|
||||
public int BranchesLimit { get; set; } = 30;
|
||||
public int CommitsLimit { get; set; } = 25;
|
||||
|
||||
private int SelectedAccountIndex
|
||||
[CustomEditor(typeof(StreamManager))]
|
||||
[CanEditMultipleObjects]
|
||||
public class StreamManagerEditor : UnityEditor.Editor
|
||||
{
|
||||
get => _streamManager.SelectedAccountIndex;
|
||||
set => _streamManager.SelectedAccountIndex = value;
|
||||
}
|
||||
private bool _foldOutAccount;
|
||||
private int _totalChildrenCount = 0;
|
||||
private StreamManager _streamManager;
|
||||
|
||||
private int SelectedStreamIndex
|
||||
{
|
||||
get => _streamManager.SelectedStreamIndex;
|
||||
set => _streamManager.SelectedStreamIndex = value;
|
||||
}
|
||||
private static bool generateAssets;
|
||||
|
||||
private int SelectedBranchIndex
|
||||
{
|
||||
get => _streamManager.SelectedBranchIndex;
|
||||
set => _streamManager.SelectedBranchIndex = value;
|
||||
}
|
||||
public int StreamsLimit { get; set; } = 30;
|
||||
public int BranchesLimit { get; set; } = 30;
|
||||
public int CommitsLimit { get; set; } = 25;
|
||||
|
||||
private int SelectedCommitIndex
|
||||
{
|
||||
get => _streamManager.SelectedCommitIndex;
|
||||
set => _streamManager.SelectedCommitIndex = value;
|
||||
}
|
||||
|
||||
private int OldSelectedAccountIndex
|
||||
{
|
||||
get => _streamManager.OldSelectedAccountIndex;
|
||||
set => _streamManager.OldSelectedAccountIndex = value;
|
||||
}
|
||||
|
||||
private int OldSelectedStreamIndex
|
||||
{
|
||||
get => _streamManager.OldSelectedStreamIndex;
|
||||
set => _streamManager.OldSelectedStreamIndex = value;
|
||||
}
|
||||
|
||||
private Client Client
|
||||
{
|
||||
get => _streamManager.Client;
|
||||
set => _streamManager.Client = value;
|
||||
}
|
||||
|
||||
private Account SelectedAccount
|
||||
{
|
||||
get => _streamManager.SelectedAccount;
|
||||
set => _streamManager.SelectedAccount = value;
|
||||
}
|
||||
|
||||
private Stream SelectedStream
|
||||
{
|
||||
get => _streamManager.SelectedStream;
|
||||
set => _streamManager.SelectedStream = value;
|
||||
}
|
||||
|
||||
public List<Account> Accounts
|
||||
{
|
||||
get => _streamManager.Accounts;
|
||||
set => _streamManager.Accounts = value;
|
||||
}
|
||||
|
||||
private List<Stream> Streams
|
||||
{
|
||||
get => _streamManager.Streams;
|
||||
set => _streamManager.Streams = value;
|
||||
}
|
||||
|
||||
private List<Branch> Branches
|
||||
{
|
||||
get => _streamManager.Branches;
|
||||
|
||||
set => _streamManager.Branches = value;
|
||||
}
|
||||
|
||||
private async Task LoadAccounts()
|
||||
{
|
||||
//refresh accounts just in case
|
||||
Accounts = AccountManager.GetAccounts().ToList();
|
||||
if (!Accounts.Any())
|
||||
{
|
||||
Debug.Log("No Accounts found, please login in Manager");
|
||||
}
|
||||
else
|
||||
{
|
||||
await SelectAccount(0);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SelectAccount(int i)
|
||||
{
|
||||
SelectedAccountIndex = i;
|
||||
OldSelectedAccountIndex = i;
|
||||
SelectedAccount = Accounts[i];
|
||||
|
||||
Client = new Client(SelectedAccount);
|
||||
await LoadStreams();
|
||||
}
|
||||
|
||||
private async Task LoadStreams()
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Loading streams...", "", 0);
|
||||
Streams = await Client.StreamsGet(StreamsLimit);
|
||||
EditorUtility.ClearProgressBar();
|
||||
if (Streams.Any())
|
||||
await SelectStream(0);
|
||||
}
|
||||
|
||||
private async Task SelectStream(int i)
|
||||
{
|
||||
SelectedStreamIndex = i;
|
||||
OldSelectedStreamIndex = i;
|
||||
SelectedStream = Streams[i];
|
||||
|
||||
EditorUtility.DisplayProgressBar("Loading stream details...", "", 0);
|
||||
Branches = await Client.StreamGetBranches(SelectedStream.id, BranchesLimit, CommitsLimit);
|
||||
if (Branches.Any())
|
||||
{
|
||||
SelectedBranchIndex = 0;
|
||||
if (Branches[SelectedBranchIndex].commits.items.Any())
|
||||
private int SelectedAccountIndex
|
||||
{
|
||||
SelectedCommitIndex = 0;
|
||||
get => _streamManager.SelectedAccountIndex;
|
||||
set => _streamManager.SelectedAccountIndex = value;
|
||||
}
|
||||
}
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
private int SelectedStreamIndex
|
||||
{
|
||||
get => _streamManager.SelectedStreamIndex;
|
||||
set => _streamManager.SelectedStreamIndex = value;
|
||||
}
|
||||
|
||||
private int SelectedBranchIndex
|
||||
{
|
||||
get => _streamManager.SelectedBranchIndex;
|
||||
set => _streamManager.SelectedBranchIndex = value;
|
||||
}
|
||||
|
||||
private async Task Receive()
|
||||
{
|
||||
var transport = new ServerTransport(SelectedAccount, SelectedStream.id);
|
||||
EditorUtility.DisplayProgressBar($"Receiving data from {transport.BaseUri}...", "", 0);
|
||||
private int SelectedCommitIndex
|
||||
{
|
||||
get => _streamManager.SelectedCommitIndex;
|
||||
set => _streamManager.SelectedCommitIndex = value;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Receive Speckle Objects
|
||||
var @base = await Operations.Receive(
|
||||
Branches[SelectedBranchIndex].commits.items[SelectedCommitIndex].referencedObject,
|
||||
remoteTransport: transport,
|
||||
onProgressAction: dict =>
|
||||
{
|
||||
UnityEditor.EditorApplication.delayCall += () =>
|
||||
private int OldSelectedAccountIndex
|
||||
{
|
||||
get => _streamManager.OldSelectedAccountIndex;
|
||||
set => _streamManager.OldSelectedAccountIndex = value;
|
||||
}
|
||||
|
||||
private int OldSelectedStreamIndex
|
||||
{
|
||||
get => _streamManager.OldSelectedStreamIndex;
|
||||
set => _streamManager.OldSelectedStreamIndex = value;
|
||||
}
|
||||
|
||||
private Client Client
|
||||
{
|
||||
get => _streamManager.Client;
|
||||
set => _streamManager.Client = value;
|
||||
}
|
||||
|
||||
private Account SelectedAccount
|
||||
{
|
||||
get => _streamManager.SelectedAccount;
|
||||
set => _streamManager.SelectedAccount = value;
|
||||
}
|
||||
|
||||
private Stream SelectedStream
|
||||
{
|
||||
get => _streamManager.SelectedStream;
|
||||
set => _streamManager.SelectedStream = value;
|
||||
}
|
||||
|
||||
public List<Account> Accounts
|
||||
{
|
||||
get => _streamManager.Accounts;
|
||||
set => _streamManager.Accounts = value;
|
||||
}
|
||||
|
||||
private List<Stream> Streams
|
||||
{
|
||||
get => _streamManager.Streams;
|
||||
set => _streamManager.Streams = value;
|
||||
}
|
||||
|
||||
private List<Branch> Branches
|
||||
{
|
||||
get => _streamManager.Branches;
|
||||
|
||||
set => _streamManager.Branches = value;
|
||||
}
|
||||
|
||||
private async Task LoadAccounts()
|
||||
{
|
||||
//refresh accounts just in case
|
||||
Accounts = AccountManager.GetAccounts().ToList();
|
||||
if (!Accounts.Any())
|
||||
{
|
||||
EditorUtility.DisplayProgressBar($"Receiving data from {transport.BaseUri}...", "",
|
||||
Convert.ToSingle(dict.Values.Average() / _totalChildrenCount));
|
||||
};
|
||||
},
|
||||
onTotalChildrenCountKnown: count => { _totalChildrenCount = count; }
|
||||
);
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
|
||||
//Convert Speckle Objects
|
||||
int childrenConverted = 0;
|
||||
void BeforeConvertCallback(Base b)
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Converting To Native...", $"{b.speckle_type} - {b.id}",
|
||||
Convert.ToSingle(childrenConverted++ / _totalChildrenCount));
|
||||
Debug.Log("No Accounts found, please login in Manager");
|
||||
}
|
||||
else
|
||||
{
|
||||
await SelectAccount(0);
|
||||
}
|
||||
}
|
||||
|
||||
var go = _streamManager.ConvertRecursivelyToNative(@base,
|
||||
Branches[SelectedBranchIndex].commits.items[SelectedCommitIndex].id, BeforeConvertCallback);
|
||||
|
||||
// Read Receipt
|
||||
await Client.CommitReceived(new CommitReceivedInput
|
||||
private async Task SelectAccount(int i)
|
||||
{
|
||||
streamId = SelectedStream.id,
|
||||
commitId = Branches[SelectedBranchIndex].commits.items[SelectedCommitIndex].id,
|
||||
message = $"received commit from {VersionedHostApplications.Unity} Editor",
|
||||
sourceApplication = VersionedHostApplications.Unity
|
||||
});
|
||||
SelectedAccountIndex = i;
|
||||
OldSelectedAccountIndex = i;
|
||||
SelectedAccount = Accounts[i];
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new SpeckleException(e.Message, e, true, SentryLevel.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorApplication.delayCall += EditorUtility.ClearProgressBar;
|
||||
}
|
||||
Client = new Client(SelectedAccount);
|
||||
await LoadStreams();
|
||||
}
|
||||
|
||||
private async Task LoadStreams()
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Loading streams...", "", 0);
|
||||
Streams = await Client.StreamsGet(StreamsLimit);
|
||||
EditorUtility.ClearProgressBar();
|
||||
if (Streams.Any())
|
||||
await SelectStream(0);
|
||||
}
|
||||
|
||||
private async Task SelectStream(int i)
|
||||
{
|
||||
SelectedStreamIndex = i;
|
||||
OldSelectedStreamIndex = i;
|
||||
SelectedStream = Streams[i];
|
||||
|
||||
EditorUtility.DisplayProgressBar("Loading stream details...", "", 0);
|
||||
Branches = await Client.StreamGetBranches(SelectedStream.id, BranchesLimit, CommitsLimit);
|
||||
if (Branches.Any())
|
||||
{
|
||||
SelectedBranchIndex = 0;
|
||||
if (Branches[SelectedBranchIndex].commits.items.Any())
|
||||
{
|
||||
SelectedCommitIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
|
||||
|
||||
private async Task Receive()
|
||||
{
|
||||
var transport = new ServerTransport(SelectedAccount, SelectedStream.id);
|
||||
EditorUtility.DisplayProgressBar($"Receiving data from {transport.BaseUri}...", "", 0);
|
||||
|
||||
try
|
||||
{
|
||||
// Receive Speckle Objects
|
||||
var @base = await Operations.Receive(
|
||||
Branches[SelectedBranchIndex].commits.items[SelectedCommitIndex].referencedObject,
|
||||
remoteTransport: transport,
|
||||
onProgressAction: dict =>
|
||||
{
|
||||
UnityEditor.EditorApplication.delayCall += () =>
|
||||
{
|
||||
EditorUtility.DisplayProgressBar($"Receiving data from {transport.BaseUri}...", "",
|
||||
Convert.ToSingle(dict.Values.Average() / _totalChildrenCount));
|
||||
};
|
||||
},
|
||||
onTotalChildrenCountKnown: count => { _totalChildrenCount = count; }
|
||||
);
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
|
||||
Analytics.TrackEvent(SelectedAccount, Analytics.Events.Receive);
|
||||
|
||||
//Convert Speckle Objects
|
||||
int childrenConverted = 0;
|
||||
|
||||
void BeforeConvertCallback(Base b)
|
||||
{
|
||||
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);
|
||||
|
||||
// Read Receipt
|
||||
await Client.CommitReceived(new CommitReceivedInput
|
||||
{
|
||||
streamId = SelectedStream.id,
|
||||
commitId = Branches[SelectedBranchIndex].commits.items[SelectedCommitIndex].id,
|
||||
message = $"received commit from {VersionedHostApplications.Unity} Editor",
|
||||
sourceApplication = VersionedHostApplications.Unity
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new SpeckleException(e.Message, e, true, SentryLevel.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorApplication.delayCall += EditorUtility.ClearProgressBar;
|
||||
}
|
||||
}
|
||||
|
||||
public override async void OnInspectorGUI()
|
||||
{
|
||||
_streamManager = (StreamManager) target;
|
||||
|
||||
|
||||
#region Account GUI
|
||||
|
||||
if (Accounts == null)
|
||||
{
|
||||
await LoadAccounts();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
SelectedAccountIndex = EditorGUILayout.Popup("Accounts", SelectedAccountIndex,
|
||||
Accounts.Select(x => x.userInfo.email + " | " + x.serverInfo.name).ToArray(),
|
||||
GUILayout.ExpandWidth(true), GUILayout.Height(20));
|
||||
|
||||
if (OldSelectedAccountIndex != SelectedAccountIndex)
|
||||
{
|
||||
await SelectAccount(SelectedAccountIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Refresh", GUILayout.Width(60), GUILayout.Height(20)))
|
||||
{
|
||||
await LoadAccounts();
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
|
||||
#region Speckle Account Info
|
||||
|
||||
_foldOutAccount = EditorGUILayout.BeginFoldoutHeaderGroup(_foldOutAccount, "Account Info");
|
||||
|
||||
if (_foldOutAccount)
|
||||
{
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
|
||||
EditorGUILayout.TextField("Name", SelectedAccount.userInfo.name,
|
||||
GUILayout.Height(20),
|
||||
GUILayout.ExpandWidth(true));
|
||||
|
||||
EditorGUILayout.TextField("Server", SelectedAccount.serverInfo.name,
|
||||
GUILayout.Height(20),
|
||||
GUILayout.ExpandWidth(true));
|
||||
|
||||
EditorGUILayout.TextField("URL", SelectedAccount.serverInfo.url,
|
||||
GUILayout.Height(20),
|
||||
GUILayout.ExpandWidth(true));
|
||||
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream List
|
||||
|
||||
if (Streams == null)
|
||||
return;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
SelectedStreamIndex = EditorGUILayout.Popup("Streams",
|
||||
SelectedStreamIndex, Streams.Select(x => x.name).ToArray(), GUILayout.Height(20),
|
||||
GUILayout.ExpandWidth(true));
|
||||
|
||||
if (OldSelectedStreamIndex != SelectedStreamIndex)
|
||||
{
|
||||
await SelectStream(SelectedStreamIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Refresh", GUILayout.Width(60), GUILayout.Height(20)))
|
||||
{
|
||||
await LoadStreams();
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Branch List
|
||||
|
||||
if (Branches == null)
|
||||
return;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
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,
|
||||
Branches[SelectedBranchIndex].commits.items.Select(x => $"{x.message} - {x.id}").ToArray(),
|
||||
GUILayout.Height(20),
|
||||
GUILayout.ExpandWidth(true));
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Generate Materials
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
GUILayout.Label("Generate assets");
|
||||
GUILayout.FlexibleSpace();
|
||||
bool selection = GUILayout.Toggle(generateAssets, "");
|
||||
if (generateAssets != selection)
|
||||
{
|
||||
|
||||
generateAssets = selection;
|
||||
_streamManager.RC.AssetCache.nativeCaches = NativeCacheFactory.GetDefaultNativeCacheSetup(generateAssets);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
bool receive = GUILayout.Button("Receive!");
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (receive)
|
||||
{
|
||||
await Receive();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override async void OnInspectorGUI()
|
||||
{
|
||||
_streamManager = (StreamManager)target;
|
||||
|
||||
|
||||
#region Account GUI
|
||||
if (Accounts == null)
|
||||
{
|
||||
await LoadAccounts();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
SelectedAccountIndex = EditorGUILayout.Popup("Accounts", SelectedAccountIndex,
|
||||
Accounts.Select(x => x.userInfo.email + " | " + x.serverInfo.name).ToArray(),
|
||||
GUILayout.ExpandWidth(true), GUILayout.Height(20));
|
||||
|
||||
if (OldSelectedAccountIndex != SelectedAccountIndex)
|
||||
{
|
||||
await SelectAccount(SelectedAccountIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Refresh", GUILayout.Width(60), GUILayout.Height(20)))
|
||||
{
|
||||
await LoadAccounts();
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
|
||||
#region Speckle Account Info
|
||||
_foldOutAccount = EditorGUILayout.BeginFoldoutHeaderGroup(_foldOutAccount, "Account Info");
|
||||
|
||||
if (_foldOutAccount)
|
||||
{
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
|
||||
EditorGUILayout.TextField("Name", SelectedAccount.userInfo.name,
|
||||
GUILayout.Height(20),
|
||||
GUILayout.ExpandWidth(true));
|
||||
|
||||
EditorGUILayout.TextField("Server", SelectedAccount.serverInfo.name,
|
||||
GUILayout.Height(20),
|
||||
GUILayout.ExpandWidth(true));
|
||||
|
||||
EditorGUILayout.TextField("URL", SelectedAccount.serverInfo.url,
|
||||
GUILayout.Height(20),
|
||||
GUILayout.ExpandWidth(true));
|
||||
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Stream List
|
||||
if (Streams == null)
|
||||
return;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
SelectedStreamIndex = EditorGUILayout.Popup("Streams",
|
||||
SelectedStreamIndex, Streams.Select(x => x.name).ToArray(), GUILayout.Height(20),
|
||||
GUILayout.ExpandWidth(true));
|
||||
|
||||
if (OldSelectedStreamIndex != SelectedStreamIndex)
|
||||
{
|
||||
await SelectStream(SelectedStreamIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Refresh", GUILayout.Width(60), GUILayout.Height(20)))
|
||||
{
|
||||
await LoadStreams();
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
#endregion
|
||||
|
||||
#region Branch List
|
||||
if (Branches == null)
|
||||
return;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
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,
|
||||
Branches[SelectedBranchIndex].commits.items.Select(x => $"{x.message} - {x.id}").ToArray(),
|
||||
GUILayout.Height(20),
|
||||
GUILayout.ExpandWidth(true));
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
#endregion
|
||||
|
||||
#region Generate Materials
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
GUILayout.Label("Generate material assets");
|
||||
GUILayout.FlexibleSpace();
|
||||
StreamManager.GenerateAssets = GUILayout.Toggle(StreamManager.GenerateAssets, "");
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
#endregion
|
||||
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
bool receive = GUILayout.Button("Receive!");
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (receive)
|
||||
{
|
||||
await Receive();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0ef3ae3dd987865439e8142619e4dbf6
|
||||
guid: 60d87a53f669b0a48b83ad5f49380332
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
|
@ -0,0 +1,90 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Speckle.Core.Models;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Speckle.ConnectorUnity.NativeCache
|
||||
{
|
||||
#nullable enable
|
||||
[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 TrySaveObject(Base speckleObject, Object nativeObject);
|
||||
|
||||
/// <summary>
|
||||
/// Prepares this <see cref="AbstractNativeCache"/> for save operations
|
||||
/// </summary>
|
||||
public virtual void BeginWrite()
|
||||
{
|
||||
isWriting = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call when finished performing save operations.
|
||||
/// Instructs the <see cref="AbstractNativeCache"/> to finish writing anything to disk
|
||||
/// </summary>
|
||||
public virtual void FinishWrite()
|
||||
{
|
||||
isWriting = false;
|
||||
}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
FinishWrite();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class AssetHelpers
|
||||
{
|
||||
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))
|
||||
{
|
||||
return string.Format(format, path, "Materials");
|
||||
}
|
||||
if (nativeType == typeof(GameObject))
|
||||
{
|
||||
return string.Format(format, path, "Prefabs");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string GetAssetName(Base speckleObject, Type nativeType)
|
||||
{
|
||||
string suffix = GetAssetSuffix(nativeType);
|
||||
var invalidChars = Path.GetInvalidFileNameChars();
|
||||
string name = GetObjectName(speckleObject);
|
||||
|
||||
string sanitisedName = new(name.Where(x => !invalidChars.Contains(x)).ToArray());
|
||||
return $"{sanitisedName}{suffix}";
|
||||
}
|
||||
|
||||
public static string GetObjectName(Base speckleObject)
|
||||
{
|
||||
string objectName = speckleObject["name"] as string ?? speckleObject.GetType().ToString();
|
||||
return $"{objectName} - {speckleObject.id}";
|
||||
}
|
||||
|
||||
|
||||
public static string GetAssetSuffix(Type nativeType)
|
||||
{
|
||||
if (nativeType == typeof(Material)) return ".mat";
|
||||
if (nativeType == typeof(GameObject)) return ".prefab";
|
||||
return ".asset";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f6cc5b1591bf7e64d9ac5f0ac97dfcf6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Speckle.ConnectorUnity.NativeCache;
|
||||
using Speckle.Core.Models;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Speckle.ConnectorUnity.NativeCache
|
||||
{
|
||||
public class AggregateNativeCache : AbstractNativeCache
|
||||
{
|
||||
[SerializeField, SerializeReference]
|
||||
public List<AbstractNativeCache> nativeCaches;
|
||||
|
||||
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;
|
||||
}
|
||||
nativeObject = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TrySaveObject(Base speckleObject, Object nativeObject)
|
||||
{
|
||||
bool hasSavedSomewhere = false;
|
||||
|
||||
foreach (var c in nativeCaches)
|
||||
{
|
||||
hasSavedSomewhere = hasSavedSomewhere || c.TrySaveObject(speckleObject, nativeObject);
|
||||
}
|
||||
|
||||
return hasSavedSomewhere;
|
||||
}
|
||||
|
||||
public override void BeginWrite()
|
||||
{
|
||||
base.BeginWrite();
|
||||
foreach (var c in nativeCaches)
|
||||
{
|
||||
c.BeginWrite();
|
||||
}
|
||||
}
|
||||
|
||||
public override void FinishWrite()
|
||||
{
|
||||
foreach (var c in nativeCaches)
|
||||
{
|
||||
try
|
||||
{
|
||||
c.FinishWrite();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
}
|
||||
base.FinishWrite();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 88d6b4f2f80eaa14f9f07505f7e44ec2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8fa50e4bdeaa3e94d942d3a9f137d91c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,153 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Speckle.Core.Models;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Speckle.ConnectorUnity.NativeCache.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Uses Unity's AssetDatabase to load existing assets from a given path
|
||||
/// </summary>
|
||||
public sealed class AssetDBNativeCache : AbstractNativeCache
|
||||
{
|
||||
public string path = "Assets/Resources";
|
||||
|
||||
private MemoryNativeCache readCache;
|
||||
|
||||
private Dictionary<Base, Object> writeBuffer = new();
|
||||
|
||||
#nullable enable
|
||||
private void Awake()
|
||||
{
|
||||
readCache = CreateInstance<MemoryNativeCache>();
|
||||
}
|
||||
|
||||
public override bool TryGetObject<T>(Base speckleObject, [NotNullWhen(true)] out T? nativeObject) where T : class
|
||||
{
|
||||
if(readCache.TryGetObject(speckleObject, out nativeObject))
|
||||
return true;
|
||||
|
||||
Type nativeType = typeof(T);
|
||||
string? folder = AssetHelpers.GetAssetFolder(nativeType, path);
|
||||
if (folder == null) return false;
|
||||
|
||||
string assetName = AssetHelpers.GetAssetName(speckleObject, nativeType);
|
||||
string assetPath = $"{folder}/{assetName}";
|
||||
|
||||
nativeObject = AssetDatabase.LoadAssetAtPath<T>(assetPath);
|
||||
return nativeObject != null;
|
||||
}
|
||||
|
||||
public override bool TrySaveObject(Base speckleObject, Object nativeObject)
|
||||
{
|
||||
writeBuffer.TryAdd(speckleObject, nativeObject);
|
||||
return readCache.TrySaveObject(speckleObject, nativeObject);
|
||||
}
|
||||
|
||||
public bool WriteObject(Base speckleObject, Object nativeObject)
|
||||
{
|
||||
Type nativeType = nativeObject.GetType();
|
||||
string? folder = AssetHelpers.GetAssetFolder(nativeType, path);
|
||||
|
||||
if (folder == null) return false;
|
||||
if (!CreateDirectory(folder)) return false;
|
||||
|
||||
string assetName = AssetHelpers.GetAssetName(speckleObject, nativeType);
|
||||
string assetPath = $"{folder}/{assetName}";
|
||||
|
||||
// Special case for GameObjects, we want to use PrefabUtility
|
||||
if (nativeObject is GameObject go)
|
||||
{
|
||||
PrefabUtility.SaveAsPrefabAssetAndConnect(go, assetPath, InteractionMode.AutomatedAction);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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: {folder}/{assetName}", this);
|
||||
return false;
|
||||
}
|
||||
|
||||
AssetDatabase.CreateAsset(nativeObject, $"{folder}/{assetName}");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void WriteAssets(IEnumerable<KeyValuePair<Base, Object>> assets)
|
||||
{
|
||||
//Write Asset Data
|
||||
try
|
||||
{
|
||||
AssetDatabase.StartAssetEditing();
|
||||
int i = 0;
|
||||
int count = writeBuffer.Count;
|
||||
foreach(var kvp in assets)
|
||||
{
|
||||
if (kvp.Value is GameObject p)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
EditorUtility.DisplayProgressBar("Writing assets", $"Writing asset for {kvp.Value.name}", (float)i / count);
|
||||
WriteObject(kvp.Key, kvp.Value);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
AssetDatabase.StopAssetEditing();
|
||||
EditorUtility.DisplayProgressBar("Writing assets", $"Finishing writing assets", 1f);
|
||||
AssetDatabase.SaveAssets();
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
}
|
||||
|
||||
public override void FinishWrite()
|
||||
{
|
||||
if (!isWriting) return;
|
||||
|
||||
var prefabs = writeBuffer.Where(x => x.Value is GameObject);
|
||||
var notPrefabs = writeBuffer.Where(x => x.Value is not GameObject);
|
||||
|
||||
WriteAssets(notPrefabs);
|
||||
WriteAssets(prefabs);
|
||||
|
||||
writeBuffer.Clear();
|
||||
if (readCache != null) readCache.LoadedAssets.Clear();
|
||||
|
||||
base.FinishWrite();
|
||||
}
|
||||
|
||||
private static bool CreateDirectory(string directoryPath)
|
||||
{
|
||||
if (Directory.Exists(directoryPath))
|
||||
return true;
|
||||
|
||||
var info = Directory.CreateDirectory(directoryPath);
|
||||
AssetDatabase.Refresh();
|
||||
return info.Exists;
|
||||
}
|
||||
|
||||
|
||||
[ContextMenu("SetPath")]
|
||||
internal void SetPath_Menu()
|
||||
{
|
||||
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}");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 141ce93d2d159c0448b5b8b33b1c0679
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "EditorCaches",
|
||||
"rootNamespace": "Speckle.ConnectorUnity",
|
||||
"references": ["GUID:05078f9b6da40444fbd72ec600449925"],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a97f36292d600f8459146719f68d6bb2
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,38 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Speckle.Core.Models;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Speckle.ConnectorUnity.NativeCache
|
||||
{
|
||||
#nullable enable
|
||||
/// <summary>
|
||||
/// In memory native object cache
|
||||
/// </summary>
|
||||
public sealed class MemoryNativeCache : AbstractNativeCache
|
||||
{
|
||||
public IDictionary<string, Object> LoadedAssets { get; set; } = new Dictionary<string, Object>();
|
||||
|
||||
public override bool TryGetObject<T>(Base speckleObject, [NotNullWhen(true)] out T? nativeObject) where T : class
|
||||
{
|
||||
if (TryGetObject(speckleObject, out Object? e) && e is T t)
|
||||
{
|
||||
nativeObject = t;
|
||||
return true;
|
||||
}
|
||||
|
||||
nativeObject = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetObject(Base speckleObject, [NotNullWhen(true)] out Object? nativeObject)
|
||||
{
|
||||
return LoadedAssets.TryGetValue(speckleObject.id, out nativeObject);
|
||||
}
|
||||
|
||||
public override bool TrySaveObject(Base speckleObject, Object nativeObject)
|
||||
{
|
||||
return LoadedAssets.TryAdd(speckleObject.id, nativeObject);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b3354e8208862c341940152f5340d41a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "NativeCaches",
|
||||
"rootNamespace": "Speckle.ConnectorUnity",
|
||||
"references": [],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 05078f9b6da40444fbd72ec600449925
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,39 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using Speckle.Core.Models;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Speckle.ConnectorUnity.NativeCache
|
||||
{
|
||||
#nullable enable
|
||||
/// <summary>
|
||||
/// Loads existing assets from <see cref="Resources"/>
|
||||
/// optionally accepting byName overrides
|
||||
/// </summary>
|
||||
public sealed class ResourcesNativeCache : AbstractNativeCache
|
||||
{
|
||||
public bool matchByName = true;
|
||||
|
||||
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;
|
||||
if (!string.IsNullOrWhiteSpace(speckleName))
|
||||
{
|
||||
nativeObject = Resources.Load<T>(speckleName);
|
||||
if (nativeObject != null) return true;
|
||||
}
|
||||
}
|
||||
|
||||
nativeObject = Resources.Load<T>(AssetHelpers.GetAssetName(speckleObject, typeof(T)));
|
||||
return nativeObject != null;
|
||||
}
|
||||
|
||||
public override bool TrySaveObject(Base speckleObject, Object nativeObject)
|
||||
{
|
||||
// Pass
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2a4a29c776298714c88f406ad39c6095
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,50 @@
|
|||
using System.Collections.Generic;
|
||||
using Speckle.ConnectorUnity.NativeCache;
|
||||
using UnityEditor.Build;
|
||||
using UnityEngine;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using Speckle.ConnectorUnity.NativeCache.Editor;
|
||||
#endif
|
||||
|
||||
namespace Speckle.ConnectorUnity
|
||||
{
|
||||
#nullable enable
|
||||
public static class NativeCacheFactory
|
||||
{
|
||||
|
||||
public static List<AbstractNativeCache> GetDefaultNativeCacheSetup(bool generateAssets = false)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (generateAssets)
|
||||
{
|
||||
return GetEditorCacheSetup();
|
||||
}
|
||||
#endif
|
||||
return GetStandaloneCacheSetup();
|
||||
|
||||
}
|
||||
|
||||
public static List<AbstractNativeCache> GetStandaloneCacheSetup()
|
||||
{
|
||||
return new List<AbstractNativeCache>()
|
||||
{
|
||||
ScriptableObject.CreateInstance<ResourcesNativeCache>(),
|
||||
ScriptableObject.CreateInstance<MemoryNativeCache>(),
|
||||
};
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static List<AbstractNativeCache> GetEditorCacheSetup()
|
||||
{
|
||||
return new List<AbstractNativeCache>()
|
||||
{
|
||||
ScriptableObject.CreateInstance<ResourcesNativeCache>(),
|
||||
ScriptableObject.CreateInstance<AssetDBNativeCache>(),
|
||||
ScriptableObject.CreateInstance<MemoryNativeCache>(),
|
||||
};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8fc80190dd595f14ca90df87fe890610
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -139,6 +139,9 @@ namespace Speckle.ConnectorUnity
|
|||
onTotalChildrenCountKnown: OnTotalChildrenCountKnown,
|
||||
disposeTransports: true
|
||||
);
|
||||
|
||||
Analytics.TrackEvent(Client.Account, Analytics.Events.Receive);
|
||||
|
||||
Dispatcher.Instance().Enqueue(() =>
|
||||
{
|
||||
var root = new GameObject()
|
||||
|
|
|
@ -3,6 +3,7 @@ using System;
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Speckle.ConnectorUnity.NativeCache;
|
||||
using Speckle.Core.Models;
|
||||
using UnityEngine;
|
||||
|
||||
|
@ -12,25 +13,34 @@ namespace Speckle.ConnectorUnity
|
|||
{
|
||||
|
||||
/// <summary>
|
||||
/// Given <paramref name="baseObject"/>,
|
||||
/// Given <paramref name="o"/>,
|
||||
/// will recursively convert any objects in the tree
|
||||
/// </summary>
|
||||
/// <param name="o">The object to convert (<see cref="Base"/> or <see cref="List{T}"/> of)</param>
|
||||
/// <param name="parent">Optional parent transform for the created root <see cref="GameObject"/>s</param>
|
||||
/// <returns> A list of all created <see cref="GameObject"/>s</returns>
|
||||
public virtual List<GameObject> RecursivelyConvertToNative(object? o, Transform? parent)
|
||||
=> RecursivelyConvertToNative(o, parent, o => ConverterInstance.CanConvertToNative(o));
|
||||
=> 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>
|
||||
public virtual List<GameObject> RecursivelyConvertToNative(object? o, Transform? parent, Func<Base, bool> predicate)
|
||||
{
|
||||
LoadMaterialOverrides();
|
||||
//Ensure we have A native cache
|
||||
if (AssetCache.nativeCaches.Any(x => x == null))
|
||||
{
|
||||
AssetCache.nativeCaches = NativeCacheFactory.GetStandaloneCacheSetup();
|
||||
}
|
||||
|
||||
ConverterInstance.SetContextDocument(AssetCache);
|
||||
AssetCache.BeginWrite();
|
||||
|
||||
var createdGameObjects = new List<GameObject>();
|
||||
ConvertChild(o, parent, predicate, createdGameObjects);
|
||||
//TODO track event
|
||||
|
||||
AssetCache.FinishWrite();
|
||||
|
||||
return createdGameObjects;
|
||||
|
||||
}
|
||||
|
@ -81,8 +91,7 @@ namespace Speckle.ConnectorUnity
|
|||
}
|
||||
|
||||
// For geometry, only traverse `elements` prop, otherwise, try and convert everything
|
||||
IEnumerable<string> potentialChildren;
|
||||
potentialChildren = ConverterInstance.CanConvertToNative(baseObject)
|
||||
IEnumerable<string> potentialChildren = ConverterInstance.CanConvertToNative(baseObject)
|
||||
? new []{"elements"}
|
||||
: baseObject.GetMemberNames();
|
||||
|
||||
|
@ -124,19 +133,6 @@ namespace Speckle.ConnectorUnity
|
|||
Debug.Log($"Unknown type {value.GetType()} found when traversing tree, will be safely ignored");
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void LoadMaterialOverrides()
|
||||
{
|
||||
//using the ContextDocument to pass materials
|
||||
//available in Assets/Materials to the converters
|
||||
Dictionary<string, UnityEngine.Object> loadedAssets = Resources.LoadAll("", typeof(Material))
|
||||
.GroupBy(o => o.name)
|
||||
.Select(o => o.First())
|
||||
.ToDictionary(o => o.name);
|
||||
|
||||
ConverterInstance.SetContextDocument(loadedAssets);
|
||||
}
|
||||
|
||||
|
||||
[Obsolete("Use RecursivelyConvertToNative instead")]
|
||||
public GameObject ConvertRecursivelyToNative(Base @base, string name)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Objects.Converter.Unity;
|
||||
using Speckle.ConnectorUnity.NativeCache;
|
||||
using Speckle.Core.Kits;
|
||||
using UnityEngine;
|
||||
|
||||
|
@ -12,7 +14,19 @@ namespace Speckle.ConnectorUnity
|
|||
[ExecuteAlways, DisallowMultipleComponent]
|
||||
public partial class RecursiveConverter : MonoBehaviour
|
||||
{
|
||||
public virtual ISpeckleConverter ConverterInstance { get; set; } = new ConverterUnity();
|
||||
|
||||
public ISpeckleConverter ConverterInstance { get; set; } = new ConverterUnity();
|
||||
|
||||
[field: SerializeField]
|
||||
public AggregateNativeCache AssetCache { get; set; }
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (AssetCache == null)
|
||||
{
|
||||
var assetCache = ScriptableObject.CreateInstance<AggregateNativeCache>();
|
||||
assetCache.nativeCaches = NativeCacheFactory.GetDefaultNativeCacheSetup();
|
||||
this.AssetCache = assetCache;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,9 @@
|
|||
"name": "Speckle.Connector",
|
||||
"rootNamespace": "Speckle.ConnectorUnity",
|
||||
"references": [
|
||||
"GUID:24f666972ea7e9149abddaae766b9c1d"
|
||||
"GUID:24f666972ea7e9149abddaae766b9c1d",
|
||||
"GUID:05078f9b6da40444fbd72ec600449925",
|
||||
"GUID:a97f36292d600f8459146719f68d6bb2"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
|
|
@ -2,81 +2,83 @@ using System;
|
|||
using Speckle.Core.Api;
|
||||
using Speckle.Core.Credentials;
|
||||
using System.Collections.Generic;
|
||||
using Speckle.ConnectorUnity.NativeCache;
|
||||
using Speckle.Core.Models;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Speckle.ConnectorUnity
|
||||
{
|
||||
[ExecuteAlways]
|
||||
[AddComponentMenu("Speckle/Stream Manager")]
|
||||
public class StreamManager : MonoBehaviour
|
||||
{
|
||||
public int SelectedAccountIndex = -1;
|
||||
public int SelectedStreamIndex = -1;
|
||||
public int SelectedBranchIndex = -1;
|
||||
public int SelectedCommitIndex = -1;
|
||||
public int OldSelectedAccountIndex = -1;
|
||||
public int OldSelectedStreamIndex = -1;
|
||||
[ExecuteAlways]
|
||||
[AddComponentMenu("Speckle/Stream Manager")]
|
||||
[RequireComponent(typeof(RecursiveConverter))]
|
||||
public class StreamManager : MonoBehaviour
|
||||
{
|
||||
public int SelectedAccountIndex = -1;
|
||||
public int SelectedStreamIndex = -1;
|
||||
public int SelectedBranchIndex = -1;
|
||||
public int SelectedCommitIndex = -1;
|
||||
public int OldSelectedAccountIndex = -1;
|
||||
public int OldSelectedStreamIndex = -1;
|
||||
|
||||
public Client Client;
|
||||
public Account SelectedAccount;
|
||||
public Stream SelectedStream;
|
||||
public Client Client;
|
||||
public Account SelectedAccount;
|
||||
public Stream SelectedStream;
|
||||
|
||||
public List<Account> Accounts;
|
||||
public List<Stream> Streams;
|
||||
public List<Branch> Branches;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static bool GenerateAssets = false;
|
||||
#endif
|
||||
|
||||
public List<Account> Accounts;
|
||||
public List<Stream> Streams;
|
||||
public List<Branch> Branches;
|
||||
|
||||
public RecursiveConverter RC { get; private set; }
|
||||
|
||||
#nullable enable
|
||||
public GameObject ConvertRecursivelyToNative(Base @base, string rootObjectName, Action<Base>? beforeConvertCallback)
|
||||
{
|
||||
private void Awake()
|
||||
{
|
||||
RC = GetComponent<RecursiveConverter>();
|
||||
}
|
||||
|
||||
|
||||
public GameObject ConvertRecursivelyToNative(Base @base, string rootObjectName,
|
||||
Action<Base>? beforeConvertCallback)
|
||||
{
|
||||
var rootObject = new GameObject(rootObjectName);
|
||||
|
||||
var rc = GetComponent<RecursiveConverter>();
|
||||
if (rc == null)
|
||||
rc = gameObject.AddComponent<RecursiveConverter>();
|
||||
|
||||
var rootObject = new GameObject(rootObjectName);
|
||||
|
||||
bool Predicate(Base o)
|
||||
{
|
||||
beforeConvertCallback?.Invoke(o);
|
||||
return rc.ConverterInstance.CanConvertToNative(o) //Accept geometry
|
||||
|| o.speckle_type == "Base" && o.totalChildrenCount > 0; // Or Base objects that have children
|
||||
}
|
||||
bool Predicate(Base o)
|
||||
{
|
||||
beforeConvertCallback?.Invoke(o);
|
||||
return RC.ConverterInstance.CanConvertToNative(o) //Accept geometry
|
||||
|| 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())
|
||||
{
|
||||
var converted = rc.RecursivelyConvertToNative(prop.Value, null, Predicate);
|
||||
|
||||
//Skip empties
|
||||
if(converted.Count <= 0) continue;
|
||||
// For the rootObject only, we will create property GameObjects
|
||||
// i.e. revit categories
|
||||
foreach (var prop in @base.GetMembers())
|
||||
{
|
||||
var converted = RC.RecursivelyConvertToNative(prop.Value, null, Predicate);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
//Skip empties
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return rootObject;
|
||||
}
|
||||
|
||||
return rootObject;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[ContextMenu("Open Speckle Stream in Browser")]
|
||||
protected void OpenUrlInBrowser()
|
||||
{
|
||||
string url = $"{SelectedAccount.serverInfo.url}/streams/{SelectedStream.id}/commits/{Branches[SelectedBranchIndex].commits.items[SelectedCommitIndex].id}";
|
||||
Application.OpenURL(url);
|
||||
}
|
||||
[ContextMenu("Open Speckle Stream in Browser")]
|
||||
protected void OpenUrlInBrowser()
|
||||
{
|
||||
string url =
|
||||
$"{SelectedAccount.serverInfo.url}/streams/{SelectedStream.id}/commits/{Branches[SelectedBranchIndex].commits.items[SelectedCommitIndex].id}";
|
||||
Application.OpenURL(url);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,2 +1,2 @@
|
|||
m_EditorVersion: 2021.3.6f1
|
||||
m_EditorVersionWithRevision: 2021.3.6f1 (7da38d85baf6)
|
||||
m_EditorVersion: 2021.3.11f1
|
||||
m_EditorVersionWithRevision: 2021.3.11f1 (0a5ca18544bf)
|
||||
|
|
Загрузка…
Ссылка в новой задаче