From 5dd117cc3a4b21f1f63fc1be336a29cbf5e96ec0 Mon Sep 17 00:00:00 2001 From: Sylvain Renault Date: Thu, 13 Jun 2024 19:39:21 +0200 Subject: [PATCH 01/13] Scripts reviewed and updated for new WS Editor. Extended some functionalities/inheritances. --- Editor/Scripts/WorldStorageInfoEditor.cs | 2 +- Runtime/Scriptables/WorldStorageServer.cs | 2 +- Runtime/Scriptables/WorldStorageUser.cs | 2 +- Runtime/Scripts/OpenAPI/BaseClient.cs | 38 +++++++++++++++++ Runtime/Scripts/OpenAPI/BaseClient.cs.meta | 11 +++++ Runtime/Scripts/OpenAPI/DataModels.cs | 23 ++++++++++ Runtime/Scripts/OpenAPI/ResponseObject.cs | 32 +++++++------- .../OpenAPI/UnityWebRequestHttpClient.cs | 20 +++++++++ Runtime/Scripts/OpenAPI/WorldStorageClient.cs | 42 ++++--------------- Runtime/Scripts/WorldStorageInfo.cs | 2 +- Runtime/Scripts/WorldStorageUnityHelper.cs | 25 +++++++++++ .../Scripts/WorldStorageUnityHelper.cs.meta | 11 +++++ Runtime/Scripts/csc.rsp.meta | 2 +- 13 files changed, 159 insertions(+), 53 deletions(-) create mode 100644 Runtime/Scripts/OpenAPI/BaseClient.cs create mode 100644 Runtime/Scripts/OpenAPI/BaseClient.cs.meta create mode 100644 Runtime/Scripts/WorldStorageUnityHelper.cs create mode 100644 Runtime/Scripts/WorldStorageUnityHelper.cs.meta diff --git a/Editor/Scripts/WorldStorageInfoEditor.cs b/Editor/Scripts/WorldStorageInfoEditor.cs index 7d7e422..89cbd53 100644 --- a/Editor/Scripts/WorldStorageInfoEditor.cs +++ b/Editor/Scripts/WorldStorageInfoEditor.cs @@ -1,7 +1,7 @@ // // ARF - Augmented Reality Framework (ETSI ISG ARF) // -// Copyright 2022 ETSI +// Copyright 2024 ETSI // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Runtime/Scriptables/WorldStorageServer.cs b/Runtime/Scriptables/WorldStorageServer.cs index 8b09622..01a2f1d 100644 --- a/Runtime/Scriptables/WorldStorageServer.cs +++ b/Runtime/Scriptables/WorldStorageServer.cs @@ -1,7 +1,7 @@ // // ARF - Augmented Reality Framework (ETSI ISG ARF) // -// Copyright 2022 ETSI +// Copyright 2024 ETSI // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Runtime/Scriptables/WorldStorageUser.cs b/Runtime/Scriptables/WorldStorageUser.cs index d00b20a..cce6247 100644 --- a/Runtime/Scriptables/WorldStorageUser.cs +++ b/Runtime/Scriptables/WorldStorageUser.cs @@ -1,7 +1,7 @@ // // ARF - Augmented Reality Framework (ETSI ISG ARF) // -// Copyright 2022 ETSI +// Copyright 2024 ETSI // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Runtime/Scripts/OpenAPI/BaseClient.cs b/Runtime/Scripts/OpenAPI/BaseClient.cs new file mode 100644 index 0000000..83fa8c3 --- /dev/null +++ b/Runtime/Scripts/OpenAPI/BaseClient.cs @@ -0,0 +1,38 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace ETSI.ARF.OpenAPI +{ + /// + /// Simple class to debug the requests + /// + public class BaseClient + { + static public bool EnableClientLog = false; + public string lastJsonText; + public long lastPayload; + + protected void _prepareRequest(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpRequestMessage request, string url) + { + if (EnableClientLog) + { + Debug.Log("[REST][URL] Send request: " + client.BaseAddress + url); + Debug.Log("[REST][URL] Send request: " + request); + } + } + + protected void _processResponse(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpResponseMessage response) + { + lastJsonText = response.Content.ReadAsStringAsync().Result.ToString(); + lastPayload = response.Content.Headers.ContentLength.Value; + + var status_ = (int)response.StatusCode; + + if (EnableClientLog) + { + Debug.Log("[REST][Data] Status: " + status_ + " Response: " + client.BaseAddress + " Len: " + lastPayload + " JSON: " + lastJsonText); + } + } + } +} \ No newline at end of file diff --git a/Runtime/Scripts/OpenAPI/BaseClient.cs.meta b/Runtime/Scripts/OpenAPI/BaseClient.cs.meta new file mode 100644 index 0000000..d0fa65b --- /dev/null +++ b/Runtime/Scripts/OpenAPI/BaseClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2e0af995ecbb4654a9191f8157a1cf0e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/OpenAPI/DataModels.cs b/Runtime/Scripts/OpenAPI/DataModels.cs index d017018..17f60fe 100644 --- a/Runtime/Scripts/OpenAPI/DataModels.cs +++ b/Runtime/Scripts/OpenAPI/DataModels.cs @@ -8,6 +8,23 @@ namespace ETSI.ARF.OpenAPI.WorldStorage public interface IModel { public System.Guid UUID { get; set; } + + public string ToJson(); + } + + // Class to monitor the server + public class Server : IModel + { + public System.Guid UUID { get; set; } + public string Name { get; set; } + + public Server(string name) + { + UUID = Guid.Empty; + Name = name; + } + + public string ToJson() { return JsonUtility.ToJson(this); } } // @@ -20,6 +37,8 @@ namespace ETSI.ARF.OpenAPI.WorldStorage UUID = Guid.NewGuid(); Name = name; } + + public string ToJson() { return JsonUtility.ToJson(this); } } public partial class WorldAnchor : IModel @@ -29,6 +48,8 @@ namespace ETSI.ARF.OpenAPI.WorldStorage UUID = Guid.NewGuid(); Name = name; } + + public string ToJson() { return JsonUtility.ToJson(this); } } public partial class WorldLink : IModel @@ -37,5 +58,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage { UUID = Guid.NewGuid(); } + + public string ToJson() { return JsonUtility.ToJson(this); } } } \ No newline at end of file diff --git a/Runtime/Scripts/OpenAPI/ResponseObject.cs b/Runtime/Scripts/OpenAPI/ResponseObject.cs index 4e6ffb7..2be59dc 100644 --- a/Runtime/Scripts/OpenAPI/ResponseObject.cs +++ b/Runtime/Scripts/OpenAPI/ResponseObject.cs @@ -15,13 +15,26 @@ using UnityEngine; namespace ETSI.ARF.OpenAPI { - public class ResponseObject + public class CancelToken + { + protected CancellationTokenSource tokenSource; + protected CancellationToken ct; + + public CancellationToken cancellationToken { get => ct; } + + public void Cancel() + { + tokenSource.Cancel(); + } + } + + public class ResponseObject : CancelToken { // Management stuffs static int ID = 0; public int transactionId = 0; public string message = ""; // custom message, type of data... - + // Time monitoring public TimeSpan DeltaTime { get => responseTime - requestTime; } public DateTime requestTime; @@ -30,34 +43,23 @@ namespace ETSI.ARF.OpenAPI // Incoming data public T result; public int payload; // size of data - + //public string result = ""; // text result //public object data = null; // custom result // Callback public Action> callback; - // Task cancelllation - public CancellationToken cancellationToken { get => ct; } - private CancellationTokenSource tokenSource; - private CancellationToken ct; - public ResponseObject(string msg, Action> func = null) { requestTime = DateTime.Now; - transactionId = ++ID; message = msg; - callback = func; + transactionId = ++ID; tokenSource = new CancellationTokenSource(); ct = tokenSource.Token; } - - public void Cancel() - { - tokenSource.Cancel(); - } } } \ No newline at end of file diff --git a/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs b/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs index 94466ce..c70ef4c 100644 --- a/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs +++ b/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs @@ -1,3 +1,23 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2024 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: June 2024 +// + // Depends on UniTask to support cancellation token and GetAwaiter: https://github.com/Cysharp/UniTask // Otherwise, the code can be adapted using https://gist.github.com/krzys-h/9062552e33dd7bd7fe4a6c12db109a1a diff --git a/Runtime/Scripts/OpenAPI/WorldStorageClient.cs b/Runtime/Scripts/OpenAPI/WorldStorageClient.cs index fd66570..55a043e 100644 --- a/Runtime/Scripts/OpenAPI/WorldStorageClient.cs +++ b/Runtime/Scripts/OpenAPI/WorldStorageClient.cs @@ -1,23 +1,3 @@ -// -// ARF - Augmented Reality Framework (ETSI ISG ARF) -// -// Copyright 2024 ETSI -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Last change: March 2024 -// - using System.Collections; using System.Collections.Generic; using UnityEngine; @@ -25,28 +5,24 @@ using UnityEngine.Networking; namespace ETSI.ARF.OpenAPI.WorldStorage { - // SylR - public partial class WorldStorageClient + /// + /// Catch the pre/pos request methods from the autogenerated classes + /// + public partial class WorldStorageClient : BaseClient { - public string lastJsonText; - public long lastPayload; - - partial void PrepareRequest(IHttpClient client, System.Net.Http.HttpRequestMessage request, string url) + partial void PrepareRequest(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpRequestMessage request, string url) { - // If needed to make some special things !!! + _prepareRequest(client, request, url); } - partial void PrepareRequest(IHttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder) + partial void PrepareRequest(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder) { // do something... } - partial void ProcessResponse(IHttpClient client, System.Net.Http.HttpResponseMessage response) + partial void ProcessResponse(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpResponseMessage response) { - lastJsonText = response.Content.ReadAsStringAsync().Result.ToString(); - lastPayload = response.Content.Headers.ContentLength.Value; - - // If needed to make some special things !!! + _processResponse(client, response); } } } \ No newline at end of file diff --git a/Runtime/Scripts/WorldStorageInfo.cs b/Runtime/Scripts/WorldStorageInfo.cs index 83421b5..ad81582 100644 --- a/Runtime/Scripts/WorldStorageInfo.cs +++ b/Runtime/Scripts/WorldStorageInfo.cs @@ -1,7 +1,7 @@ // // ARF - Augmented Reality Framework (ETSI ISG ARF) // -// Copyright 2022 ETSI +// Copyright 2024 ETSI // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Runtime/Scripts/WorldStorageUnityHelper.cs b/Runtime/Scripts/WorldStorageUnityHelper.cs new file mode 100644 index 0000000..0a5478e --- /dev/null +++ b/Runtime/Scripts/WorldStorageUnityHelper.cs @@ -0,0 +1,25 @@ +using ETSI.ARF.OpenAPI.WorldStorage; +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class WorldStorageUnityHelper +{ + /// + /// Convert a float array of length 16 to a Matrix + /// + /// the values to convert + /// Converted Unity Matrix + public static ETSI.ARF.OpenAPI.WorldStorage.Transform3D ConvertUnityToETSIARFTransform3D(Matrix4x4 value) + { + Transform3D result = new Transform3D + { + value.m00, value.m01, value.m02, value.m03, + value.m10, value.m11, value.m12, value.m13, + value.m20, value.m21, value.m22, value.m23, + value.m30, value.m31, value.m32, value.m33, + }; + return result; + } +} diff --git a/Runtime/Scripts/WorldStorageUnityHelper.cs.meta b/Runtime/Scripts/WorldStorageUnityHelper.cs.meta new file mode 100644 index 0000000..8ef5dba --- /dev/null +++ b/Runtime/Scripts/WorldStorageUnityHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dc92958843a03644e8524fd2312c3f42 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/csc.rsp.meta b/Runtime/Scripts/csc.rsp.meta index 8c85794..773242b 100644 --- a/Runtime/Scripts/csc.rsp.meta +++ b/Runtime/Scripts/csc.rsp.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a94d6effd437d7842907e9a5cfd2732f +guid: 7cf3a1fe1b3964e41afa78147db793b0 DefaultImporter: externalObjects: {} userData: -- GitLab From 8d0b687c978d5319b2903b24bf9e63b289c7777f Mon Sep 17 00:00:00 2001 From: Sylvain Renault Date: Fri, 14 Jun 2024 13:37:44 +0200 Subject: [PATCH 02/13] Changes to new NSwag system was done. --- Runtime/Scripts/REST/AdminRequest.cs | 6 +- Runtime/Scripts/REST/RequestBase.cs | 4 +- Runtime/Scripts/REST/TrackableRequest.cs | 16 ++-- Runtime/Scripts/REST/WorldAnchorRequest.cs | 102 +++++++++++++------- Runtime/Scripts/REST/WorldLinkRequest.cs | 105 +++++++++++++-------- Runtime/Scripts/WorldStorageUnityHelper.cs | 48 ++++++++++ 6 files changed, 193 insertions(+), 88 deletions(-) diff --git a/Runtime/Scripts/REST/AdminRequest.cs b/Runtime/Scripts/REST/AdminRequest.cs index 36492dc..cf2304b 100644 --- a/Runtime/Scripts/REST/AdminRequest.cs +++ b/Runtime/Scripts/REST/AdminRequest.cs @@ -48,7 +48,7 @@ namespace ETSI.ARF.WorldStorage.REST var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("Request Ping..."); + Debug.Log("[REST] Request Ping..."); ResponseObject ro = new ResponseObject("Request Ping", func); apiClient.GetPingAsync().ContinueWith(OnReceiveObject, ro); return ro; @@ -60,7 +60,7 @@ namespace ETSI.ARF.WorldStorage.REST var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("Request Admin..."); + Debug.Log("[REST] Request Admin..."); ResponseObject ro = new ResponseObject("Request Admin", func); apiClient.GetAdminAsync().ContinueWith(OnReceiveObject, ro); return ro; @@ -72,7 +72,7 @@ namespace ETSI.ARF.WorldStorage.REST var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("Request Version..."); + Debug.Log("[REST] Request Version..."); ResponseObject ro = new ResponseObject("Request Version", func); apiClient.GetVersionAsync().ContinueWith(OnReceiveObject, ro); return ro; diff --git a/Runtime/Scripts/REST/RequestBase.cs b/Runtime/Scripts/REST/RequestBase.cs index 4d98fb2..776541f 100644 --- a/Runtime/Scripts/REST/RequestBase.cs +++ b/Runtime/Scripts/REST/RequestBase.cs @@ -49,11 +49,11 @@ namespace ETSI.ARF.WorldStorage.REST ResponseObject o = (ResponseObject)id; o.responseTime = DateTime.Now; o.result = t.Result; - Debug.Log($"Server Response = {o.result} (ID={o.transactionId}, Msg={o.message})"); + Debug.Log($"[REST] Server Response = {o.result.ToString()} (ID={o.transactionId}, Msg={o.message})"); o.callback?.Invoke(o); } - else Debug.Log("OpenAPI Timeout!"); + else Debug.Log("[REST] OpenAPI Timeout!"); } static protected void OnReceiveListOfObjects(Task> t, object id) where TObj : IModel diff --git a/Runtime/Scripts/REST/TrackableRequest.cs b/Runtime/Scripts/REST/TrackableRequest.cs index 4712c42..73f5fe3 100644 --- a/Runtime/Scripts/REST/TrackableRequest.cs +++ b/Runtime/Scripts/REST/TrackableRequest.cs @@ -15,18 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// Last change: March 2024 +// Last change: June 2024 // -#define USING_OPENAPI_GENERATOR // alt. is Swagger - using System; using System.Collections.Generic; using System.Threading.Tasks; using UnityEngine; -using ETSI.ARF.OpenAPI.WorldStorage; using ETSI.ARF.OpenAPI; +using ETSI.ARF.OpenAPI.WorldStorage; namespace ETSI.ARF.WorldStorage.REST { @@ -41,7 +39,7 @@ namespace ETSI.ARF.WorldStorage.REST var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("Request 1 Trackable..."); + Debug.Log("[REST] Request 1 Trackable..."); ResponseObject ro = new ResponseObject("Request Trackable " + UUID.ToString(), func); apiClient.GetTrackableByIdAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; @@ -53,7 +51,7 @@ namespace ETSI.ARF.WorldStorage.REST var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("Request Trackables..."); + Debug.Log("[REST] Request Trackables..."); ResponseObject> ro = new ResponseObject>("Request Trackables", func); apiClient.GetTrackablesAsync(token, ro.cancellationToken).ContinueWith(OnReceiveListOfObjects, ro); return ro; @@ -65,7 +63,7 @@ namespace ETSI.ARF.WorldStorage.REST var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("Create 1 Trackable..."); + Debug.Log("[REST] Create 1 Trackable..."); // Add some management stuffs trackable.UUID = Guid.NewGuid(); @@ -82,7 +80,7 @@ namespace ETSI.ARF.WorldStorage.REST var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("Update Trackable..."); + Debug.Log("[REST] Update Trackable..."); ResponseObject ro = new ResponseObject("Update Trackable " + trackable.UUID.ToString(), func); apiClient.ModifyTrackableAsync(token, trackable,ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; @@ -93,7 +91,7 @@ namespace ETSI.ARF.WorldStorage.REST var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("Delete 1 Trackable..."); + Debug.Log("[REST] Delete 1 Trackable..."); ResponseObject ro = new ResponseObject("Delete Trackable " + UUID.ToString(), func); apiClient.DeleteTrackableAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; diff --git a/Runtime/Scripts/REST/WorldAnchorRequest.cs b/Runtime/Scripts/REST/WorldAnchorRequest.cs index db10a38..7ed1418 100644 --- a/Runtime/Scripts/REST/WorldAnchorRequest.cs +++ b/Runtime/Scripts/REST/WorldAnchorRequest.cs @@ -18,55 +18,85 @@ // Last change: March 2024 // +using System; using System.Collections.Generic; +using System.Threading.Tasks; using UnityEngine; +using ETSI.ARF.OpenAPI; using ETSI.ARF.OpenAPI.WorldStorage; //#if UNITY_EDITOR namespace ETSI.ARF.WorldStorage.REST { - public class WorldAnchorRequest + public class WorldAnchorRequest : RequestBase { - //static public string AddWorldAnchor(WorldStorageServer ws, WorldAnchor anchor) - //{ - // Debug.Log("Posting Add World Anchor to Server"); - // WorldAnchorsApi api = new WorldAnchorsApi(ws.URI); - // string result = api.AddWorldAnchor(anchor); - // Debug.Log(result); - // return result; - //} + // + // Wrapper for the endpoints + // + static public ResponseObject GetWorldAnchorAsync(WorldStorageServer ws, Guid UUID, Action> func) + { + wsServer = ws; + var httpClient = new UnityWebRequestHttpClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); - //static public string UpdateWorldAnchor(WorldStorageServer ws, WorldAnchor anchor) - //{ - // Debug.Log("Posting Add World Anchor to Server"); - // WorldAnchorsApi api = new WorldAnchorsApi(ws.URI); - // string result = api.ModifyWorldAnchor(anchor); - // Debug.Log(result); - // return result; - //} + Debug.Log("[REST] Request 1 WorldAnchor..."); + ResponseObject ro = new ResponseObject("Request WorldAnchor " + UUID.ToString(), func); + apiClient.GetWorldAnchorByIdAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + return ro; + } - //static public List GetAllWorldAnchors(WorldStorageServer ws) - //{ - // WorldAnchorsApi api = new WorldAnchorsApi(ws.URI); - // List result = api.GetWorldAnchors(); - // return result; - //} + static public ResponseObject> GetWorldAnchorsAsync(WorldStorageServer ws, Action>> func) + { + wsServer = ws; + var httpClient = new UnityWebRequestHttpClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); - //static public WorldAnchor GetWorldAnchor(WorldStorageServer ws, string uuid) - //{ - // System.Guid _uuid = System.Guid.Parse(uuid); - // WorldAnchorsApi api = new WorldAnchorsApi(ws.URI); - // WorldAnchor result = api.GetWorldAnchorById(_uuid); - // return result; - //} + Debug.Log("[REST] Request WorldAnchors..."); + ResponseObject> ro = new ResponseObject>("Request WorldAnchors", func); + apiClient.GetWorldAnchorsAsync(token, ro.cancellationToken).ContinueWith(OnReceiveListOfObjects, ro); + return ro; + } - //static public void DeleteWorldAnchor(WorldStorageServer ws, string uuid) - //{ - // System.Guid _uuid = System.Guid.Parse(uuid); - // WorldAnchorsApi api = new WorldAnchorsApi(ws.URI); - // api.DeleteWorldAnchor(_uuid); - //} + static public ResponseObject CreateWorldAnchorAsync(WorldStorageServer ws, WorldAnchor worldAnchor, Action> func) + { + wsServer = ws; + var httpClient = new UnityWebRequestHttpClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log("[REST] Create 1 WorldAnchor..."); + + // Add some management stuffs + worldAnchor.UUID = Guid.NewGuid(); + worldAnchor.CreatorUUID = Guid.Empty; + + ResponseObject ro = new ResponseObject("Create WorldAnchor " + worldAnchor.Name + " (no UUID)", func); + apiClient.AddWorldAnchorAsync(token, worldAnchor, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + return ro; + } + + static public ResponseObject UpdateWorldAnchorAsync(WorldStorageServer ws, WorldAnchor worldAnchor, Action> func) + { + wsServer = ws; + var httpClient = new UnityWebRequestHttpClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log("[REST] Update WorldAnchor..."); + ResponseObject ro = new ResponseObject("Update WorldAnchor " + worldAnchor.UUID.ToString(), func); + apiClient.ModifyWorldAnchorAsync(token, worldAnchor, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + return ro; + } + static public ResponseObject DeleteWorldAnchorAsync(WorldStorageServer ws, Guid UUID, Action> func) + { + wsServer = ws; + var httpClient = new UnityWebRequestHttpClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log("[REST] Delete 1 WorldAnchor..."); + ResponseObject ro = new ResponseObject("Delete WorldAnchor " + UUID.ToString(), func); + apiClient.DeleteWorldAnchorAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + return ro; + } } } //#endif \ No newline at end of file diff --git a/Runtime/Scripts/REST/WorldLinkRequest.cs b/Runtime/Scripts/REST/WorldLinkRequest.cs index 07a6c3f..2ea9ef3 100644 --- a/Runtime/Scripts/REST/WorldLinkRequest.cs +++ b/Runtime/Scripts/REST/WorldLinkRequest.cs @@ -15,58 +15,87 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// Last change: March 2024 +// Last change: June 2024 // +using System; using System.Collections.Generic; +using System.Threading.Tasks; using UnityEngine; +using ETSI.ARF.OpenAPI; using ETSI.ARF.OpenAPI.WorldStorage; -//#if UNITY_EDITOR namespace ETSI.ARF.WorldStorage.REST { - public class WorldLinkRequest + public class WorldLinkRequest : RequestBase { - //static public string AddWorldLink(WorldStorageServer ws, WorldLink link) - //{ - // Debug.Log("Posting Add Trackable to Server"); - // WorldLinksApi api = new WorldLinksApi(ws.URI); - // string result = api.AddWorldLink(link); - // Debug.Log(result); - // return result; - //} + // + // Wrapper for the endpoints + // + static public ResponseObject GetWorldLinkAsync(WorldStorageServer ws, Guid UUID, Action> func) + { + wsServer = ws; + var httpClient = new UnityWebRequestHttpClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); - //static public string UpdateWorldLink(WorldStorageServer ws, WorldLink link) - //{ - // Debug.Log("Posting Add Trackable to Server"); - // WorldLinksApi api = new WorldLinksApi(ws.URI); - // string result = api.ModifyWorldLink(link); - // Debug.Log(result); - // return result; - //} + Debug.Log("[REST] Request 1 WorldLink..."); + ResponseObject ro = new ResponseObject("Request WorldLink " + UUID.ToString(), func); + apiClient.GetWorldLinkByIdAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + return ro; + } - //static public List GetAllWorldLinks(WorldStorageServer ws) - //{ - // WorldLinksApi api = new WorldLinksApi(ws.URI); - // List result = api.GetWorldLinks(); - // return result; - //} + static public ResponseObject> GetWorldLinksAsync(WorldStorageServer ws, Action>> func) + { + wsServer = ws; + var httpClient = new UnityWebRequestHttpClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); - //static public WorldLink GetWorldLink(WorldStorageServer ws, string uuid) - //{ - // System.Guid _uuid = System.Guid.Parse(uuid); - // WorldLinksApi api = new WorldLinksApi(ws.URI); - // WorldLink result = api.GetWorldLinkById(_uuid); - // return result; - //} + Debug.Log("[REST] Request WorldLinks..."); + ResponseObject> ro = new ResponseObject>("Request WorldLinks", func); + apiClient.GetWorldLinksAsync(token, ro.cancellationToken).ContinueWith(OnReceiveListOfObjects, ro); + return ro; + } - //static public void DeleteWorldLink(WorldStorageServer ws, string uuid) - //{ - // System.Guid _uuid = System.Guid.Parse(uuid); - // WorldLinksApi api = new WorldLinksApi(ws.URI); - // api.DeleteWorldLink(_uuid); - //} + static public ResponseObject CreateWorldLinkAsync(WorldStorageServer ws, WorldLink worldLink, Action> func) + { + wsServer = ws; + var httpClient = new UnityWebRequestHttpClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log("[REST] Create 1 WorldLink..."); + + // Add some management stuffs + worldLink.UUID = Guid.NewGuid(); + worldLink.CreatorUUID = Guid.Empty; + + ResponseObject ro = new ResponseObject("Create WorldLink (no UUID)", func); + apiClient.AddWorldLinkAsync(token, worldLink, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + return ro; + } + + static public ResponseObject UpdateWorldLinkAsync(WorldStorageServer ws, WorldLink worldLink, Action> func) + { + wsServer = ws; + var httpClient = new UnityWebRequestHttpClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log("[REST] Update WorldLink..."); + ResponseObject ro = new ResponseObject("Update WorldLink " + worldLink.UUID.ToString(), func); + apiClient.ModifyWorldLinkAsync(token, worldLink, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + return ro; + } + static public ResponseObject DeleteWorldLinkAsync(WorldStorageServer ws, Guid UUID, Action> func) + { + wsServer = ws; + var httpClient = new UnityWebRequestHttpClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log("[REST] Delete 1 WorldLink..."); + ResponseObject ro = new ResponseObject("Delete WorldLink " + UUID.ToString(), func); + apiClient.DeleteWorldLinkAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + return ro; + } } } //#endif \ No newline at end of file diff --git a/Runtime/Scripts/WorldStorageUnityHelper.cs b/Runtime/Scripts/WorldStorageUnityHelper.cs index 0a5478e..30cc44b 100644 --- a/Runtime/Scripts/WorldStorageUnityHelper.cs +++ b/Runtime/Scripts/WorldStorageUnityHelper.cs @@ -22,4 +22,52 @@ public class WorldStorageUnityHelper }; return result; } + + /// + /// Convert a float array of length 16 to a Matrix + /// + /// the values to convert + /// Converted Unity Matrix + public static Matrix4x4 ConvertETSIARFTransform3DToUnity(ETSI.ARF.OpenAPI.WorldStorage.Transform3D value) + { + if (value.Count == 16) + { + Matrix4x4 resul = new Matrix4x4(); + resul[0, 0] = value[0]; + resul[0, 1] = value[1]; + resul[0, 2] = value[2]; + resul[0, 3] = value[3]; + + resul[1, 0] = value[4]; + resul[1, 1] = value[5]; + resul[1, 2] = value[6]; + resul[1, 3] = value[7]; + + resul[2, 0] = value[8]; + resul[2, 1] = value[9]; + resul[2, 2] = value[10]; + resul[2, 3] = value[11]; + + resul[3, 0] = value[12]; + resul[3, 1] = value[13]; + resul[3, 2] = value[14]; + resul[3, 3] = value[15]; + + return resul; + } + else + { + throw new ArgumentException("The numer of floats in the value parameter must be 16!"); + } + } + + static public Matrix4x4 MatrixFromLocalCRS(List value) + { + Matrix4x4 result = new Matrix4x4(); + result.m00 = value[0]; result.m01 = value[1]; result.m02 = value[2]; result.m03 = value[3]; + result.m10 = value[4]; result.m11 = value[5]; result.m12 = value[6]; result.m13 = value[7]; + result.m20 = value[8]; result.m21 = value[9]; result.m22 = value[10]; result.m23 = value[11]; + result.m30 = value[12]; result.m31 = value[13]; result.m32 = value[14]; result.m33 = value[15]; + return result; + } } -- GitLab From fbe3790e81f4e5ce7d3837aaa28171f61fd9aec4 Mon Sep 17 00:00:00 2001 From: Sylvain Renault Date: Mon, 17 Jun 2024 11:38:43 +0200 Subject: [PATCH 03/13] Updated user values/names (scriptables) Updated openapi test scene. --- Runtime/Scenes/OpenAPITest.cs | 23 +++++++-- Runtime/Scenes/Package Test.unity | 72 ++++++++++++++--------------- Runtime/Scenes/User ETSI.asset | 17 +++++++ Runtime/Scenes/User ETSI.asset.meta | 8 ++++ 4 files changed, 79 insertions(+), 41 deletions(-) create mode 100644 Runtime/Scenes/User ETSI.asset create mode 100644 Runtime/Scenes/User ETSI.asset.meta diff --git a/Runtime/Scenes/OpenAPITest.cs b/Runtime/Scenes/OpenAPITest.cs index a9f75a6..b3fa21c 100644 --- a/Runtime/Scenes/OpenAPITest.cs +++ b/Runtime/Scenes/OpenAPITest.cs @@ -15,6 +15,7 @@ public class OpenAPITest : MonoBehaviour public TMP_Text servername; public TMP_Text output; + private string serverState = "-"; private string msg = null; private Queue handleResponseQ = new Queue(); @@ -41,7 +42,7 @@ public class OpenAPITest : MonoBehaviour if (o is ResponseObject) { ResponseObject response = o as ResponseObject; - output.text = $"Request Time: { response.requestTime.ToLongTimeString() } / Total Time: { response.DeltaTime.TotalMilliseconds }ms\n\nContent:\n{ response.result }"; + output.text = $"Server State:\n\n{ serverState }"; } else if (o is ResponseObject) { @@ -62,7 +63,7 @@ public class OpenAPITest : MonoBehaviour } } - public void OnButtonClick_TestPing() + public void OnButtonClick_ServerTest() { if (server == null) { @@ -70,11 +71,23 @@ public class OpenAPITest : MonoBehaviour return; } - ResponseObject token = AdminRequest.PingAsync(server, (response) => + serverState = $"Requesting server state @ time: { DateTime.Now.ToLongTimeString() }...\n"; + + AdminRequest.PingAsync(server, (response1) => { - handleResponseQ.Enqueue(response); + serverState += $"\nSending: Ping\n Receiving: { response1.result }\n Req time: { response1.requestTime.ToLongTimeString() } Tot time: { response1.DeltaTime.TotalMilliseconds }"; + handleResponseQ.Enqueue(response1); + }); + AdminRequest.AdminAsync(server, (response2) => + { + serverState += $"\nSending: Admin\n Receiving: { response2.result }\n Req time: { response2.requestTime.ToLongTimeString() } Tot time: { response2.DeltaTime.TotalMilliseconds }"; + handleResponseQ.Enqueue(response2); + }); + AdminRequest.VersionAsync(server, (response3) => + { + serverState += $"\nSending: Version\n Receiving: { response3.result }\n Req time: { response3.requestTime.ToLongTimeString() } Tot time: { response3.DeltaTime.TotalMilliseconds }"; + handleResponseQ.Enqueue(response3); }); - output.text = "Starting request @ time: " + token.requestTime.ToLongTimeString() + "..."; } public void OnButtonClick_GetLastTrackable() diff --git a/Runtime/Scenes/Package Test.unity b/Runtime/Scenes/Package Test.unity index 607faa7..89c08f9 100644 --- a/Runtime/Scenes/Package Test.unity +++ b/Runtime/Scenes/Package Test.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.44402242, g: 0.49316543, b: 0.5722324, a: 1} + m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -189,8 +189,8 @@ MonoBehaviour: m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + rgba: 4278190080 + m_fontColor: {r: 0, g: 0, b: 0, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -207,8 +207,8 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 36 - m_fontSizeBase: 36 + m_fontSize: 32 + m_fontSizeBase: 32 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 0 @@ -399,8 +399,8 @@ MonoBehaviour: m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + rgba: 4278190080 + m_fontColor: {r: 0, g: 0, b: 0, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -417,8 +417,8 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 36 - m_fontSizeBase: 36 + m_fontSize: 32 + m_fontSizeBase: 32 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 0 @@ -480,7 +480,7 @@ GameObject: - component: {fileID: 485599440} - component: {fileID: 485599439} m_Layer: 5 - m_Name: Button Ping + m_Name: Button WS State m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -551,8 +551,8 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 2123268211} - m_TargetAssemblyTypeName: OpenAPITest, Assembly-CSharp - m_MethodName: OnButtonClick_TestPing + m_TargetAssemblyTypeName: OpenAPITest, etsi.isg.arf.worldstorage + m_MethodName: OnButtonClick_ServerTest m_Mode: 1 m_Arguments: m_ObjectArgument: {fileID: 0} @@ -611,7 +611,7 @@ GameObject: - component: {fileID: 491226576} - component: {fileID: 491226577} m_Layer: 5 - m_Name: Buttons + m_Name: UI m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -643,7 +643,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 32, y: -200} + m_AnchoredPosition: {x: 32, y: 0} m_SizeDelta: {x: -64, y: 400} m_Pivot: {x: 0, y: 1} --- !u!114 &491226577 @@ -995,7 +995,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: Request trackables + m_text: Request all trackables m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} @@ -1004,8 +1004,8 @@ MonoBehaviour: m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + rgba: 4278190080 + m_fontColor: {r: 0, g: 0, b: 0, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -1022,8 +1022,8 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 36 - m_fontSizeBase: 36 + m_fontSize: 32 + m_fontSizeBase: 32 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 0 @@ -1373,8 +1373,8 @@ MonoBehaviour: m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + rgba: 4278190080 + m_fontColor: {r: 0, g: 0, b: 0, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -1391,8 +1391,8 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 36 - m_fontSizeBase: 36 + m_fontSize: 32 + m_fontSizeBase: 32 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 0 @@ -2042,8 +2042,8 @@ MonoBehaviour: m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + rgba: 4278190080 + m_fontColor: {r: 0, g: 0, b: 0, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -2060,8 +2060,8 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 36 - m_fontSizeBase: 36 + m_fontSize: 32 + m_fontSizeBase: 32 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 0 @@ -2145,7 +2145,7 @@ Camera: m_GameObject: {fileID: 1900725046} m_Enabled: 1 serializedVersion: 2 - m_ClearFlags: 1 + m_ClearFlags: 2 m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} m_projectionMatrixMode: 1 m_GateFitMode: 2 @@ -2380,8 +2380,8 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 36 - m_fontSizeBase: 36 + m_fontSize: 30 + m_fontSizeBase: 30 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 @@ -2688,7 +2688,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: Ping + m_text: Get WS server state m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} @@ -2697,8 +2697,8 @@ MonoBehaviour: m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + rgba: 4278190080 + m_fontColor: {r: 0, g: 0, b: 0, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -2715,8 +2715,8 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 36 - m_fontSizeBase: 36 + m_fontSize: 32 + m_fontSizeBase: 32 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 0 @@ -2794,7 +2794,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 8d8b78014fb03e94c90db2fa1a2fde7b, type: 3} m_Name: m_EditorClassIdentifier: - server: {fileID: 11400000, guid: e58ba3b536eb26a4d899273c538c88e7, type: 2} + server: {fileID: 11400000, guid: a3bbdc2753015174d9cf466761005897, type: 2} servername: {fileID: 1270536910} output: {fileID: 1973593797} --- !u!4 &2123268212 diff --git a/Runtime/Scenes/User ETSI.asset b/Runtime/Scenes/User ETSI.asset new file mode 100644 index 0000000..a88ab2e --- /dev/null +++ b/Runtime/Scenes/User ETSI.asset @@ -0,0 +1,17 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +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: 8a1e3e7961eae84468e6ee20d5b09ffd, type: 3} + m_Name: User ETSI + m_EditorClassIdentifier: + userName: ARF User + company: ETSI Org + UUID: 5090fd9f-64bf-4e06-843f-26aaf2eb8e40 diff --git a/Runtime/Scenes/User ETSI.asset.meta b/Runtime/Scenes/User ETSI.asset.meta new file mode 100644 index 0000000..08ca9e2 --- /dev/null +++ b/Runtime/Scenes/User ETSI.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 748585a50399fd64883147cd731ae0b7 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: -- GitLab From cebe3c24911db848f91ced30955be6bca4974a71 Mon Sep 17 00:00:00 2001 From: Sylvain Renault Date: Fri, 12 Jul 2024 20:05:33 +0200 Subject: [PATCH 04/13] Creator ID is set to default if Empty. An Empty value cause a problem by the JSON interpretation (NSwag?). --- Runtime/Scenes/Package Test.unity | 2018 ++++++++++++++++++-- Runtime/Scripts/REST/TrackableRequest.cs | 6 +- Runtime/Scripts/REST/WorldAnchorRequest.cs | 4 +- Runtime/Scripts/REST/WorldLinkRequest.cs | 4 +- 4 files changed, 1900 insertions(+), 132 deletions(-) diff --git a/Runtime/Scenes/Package Test.unity b/Runtime/Scenes/Package Test.unity index 89c08f9..a112c3d 100644 --- a/Runtime/Scenes/Package Test.unity +++ b/Runtime/Scenes/Package Test.unity @@ -257,6 +257,179 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 67681887} m_CullTransparentMesh: 1 +--- !u!1 &181827838 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 181827839} + m_Layer: 0 + m_Name: c5dafaa0-a64e-44fc-98a7-f0f60bd181b0 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &181827839 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 181827838} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 976672958} + - {fileID: 1650656169} + m_Father: {fileID: 1006052647} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &216668784 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 216668785} + - component: {fileID: 216668788} + - component: {fileID: 216668787} + - component: {fileID: 216668786} + m_Layer: 0 + m_Name: Center + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &216668785 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 216668784} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.1, y: 0.1, z: 0.1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 313423862} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &216668786 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 216668784} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &216668787 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 216668784} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 4f607925b7a7fcc44806b35f5aa087a4, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &216668788 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 216668784} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &313423861 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 313423862} + m_Layer: 0 + m_Name: Axe + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &313423862 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 313423861} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 216668785} + - {fileID: 1877813050} + - {fileID: 2116690940} + - {fileID: 1685018303} + m_Father: {fileID: 1035254689} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &395487864 GameObject: m_ObjectHideFlags: 0 @@ -938,6 +1111,111 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 517791554} m_CullTransparentMesh: 1 +--- !u!1 &607234448 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 607234449} + - component: {fileID: 607234452} + - component: {fileID: 607234451} + - component: {fileID: 607234450} + m_Layer: 0 + m_Name: Center + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &607234449 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 607234448} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 1, z: 0, w: 0} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.1, y: 0.1, z: 0.1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 976672958} + m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0} +--- !u!65 &607234450 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 607234448} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &607234451 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 607234448} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 730ea8fe50af5874fb3b990c534eaebc, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &607234452 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 607234448} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} --- !u!1 &768727573 GameObject: m_ObjectHideFlags: 0 @@ -1307,6 +1585,107 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 925389933} m_CullTransparentMesh: 1 +--- !u!1 &976672957 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 976672958} + m_Layer: 0 + m_Name: Axe + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &976672958 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 976672957} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 607234449} + - {fileID: 1580568510} + - {fileID: 1802205027} + - {fileID: 1614791896} + m_Father: {fileID: 181827839} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1006052646 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1006052647} + m_Layer: 0 + m_Name: ARF Visuals + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1006052647 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1006052646} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1035254689} + - {fileID: 181827839} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1035254688 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1035254689} + m_Layer: 0 + m_Name: 80153adf-b32c-4f77-a374-b20a92c822d1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1035254689 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1035254688} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 313423862} + - {fileID: 1564988513} + m_Father: {fileID: 1006052647} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1064828074 GameObject: m_ObjectHideFlags: 0 @@ -1441,7 +1820,7 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1064828074} m_CullTransparentMesh: 1 ---- !u!1 &1144814801 +--- !u!1 &1087987906 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1449,42 +1828,42 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1144814802} - - component: {fileID: 1144814804} - - component: {fileID: 1144814803} + - component: {fileID: 1087987907} + - component: {fileID: 1087987909} + - component: {fileID: 1087987908} m_Layer: 5 - m_Name: Label + m_Name: Text m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1144814802 +--- !u!224 &1087987907 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1144814801} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_GameObject: {fileID: 1087987906} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 + m_LocalScale: {x: 0.001, y: 0.001, z: 0.001} + m_ConstrainProportionsScale: 1 m_Children: [] - m_Father: {fileID: 491226576} + m_Father: {fileID: 1650656169} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 100} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -0.025} + m_SizeDelta: {x: 250, y: 50} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1144814803 +--- !u!114 &1087987908 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1144814801} + m_GameObject: {fileID: 1087987906} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} @@ -1498,7 +1877,9 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: 'Response:' + m_text: 'Name: Default Anchor + + UUID: c5dafaa0-a64e-44fc-98a7-f0f60bd181b0' m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} @@ -1525,15 +1906,15 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 36 - m_fontSizeBase: 36 + m_fontSize: 16 + m_fontSizeBase: 16 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 m_fontSizeMax: 72 - m_fontStyle: 4 + m_fontStyle: 0 m_HorizontalAlignment: 1 - m_VerticalAlignment: 512 + m_VerticalAlignment: 256 m_textAlignment: 65535 m_characterSpacing: 0 m_wordSpacing: 0 @@ -1567,15 +1948,15 @@ MonoBehaviour: m_hasFontAssetChanged: 0 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!222 &1144814804 +--- !u!222 &1087987909 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1144814801} + m_GameObject: {fileID: 1087987906} m_CullTransparentMesh: 1 ---- !u!1 &1270536908 +--- !u!1 &1144814801 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1583,23 +1964,23 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1270536909} - - component: {fileID: 1270536911} - - component: {fileID: 1270536910} + - component: {fileID: 1144814802} + - component: {fileID: 1144814804} + - component: {fileID: 1144814803} m_Layer: 5 - m_Name: Server + m_Name: Label m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1270536909 +--- !u!224 &1144814802 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1270536908} + m_GameObject: {fileID: 1144814801} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} @@ -1612,13 +1993,13 @@ RectTransform: m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 100} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1270536910 +--- !u!114 &1144814803 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1270536908} + m_GameObject: {fileID: 1144814801} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} @@ -1632,7 +2013,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: 'ARF Server: -' + m_text: 'Response:' m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} @@ -1665,7 +2046,7 @@ MonoBehaviour: m_enableAutoSizing: 0 m_fontSizeMin: 18 m_fontSizeMax: 72 - m_fontStyle: 1 + m_fontStyle: 4 m_HorizontalAlignment: 1 m_VerticalAlignment: 512 m_textAlignment: 65535 @@ -1701,15 +2082,15 @@ MonoBehaviour: m_hasFontAssetChanged: 0 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!222 &1270536911 +--- !u!222 &1144814804 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1270536908} + m_GameObject: {fileID: 1144814801} m_CullTransparentMesh: 1 ---- !u!1 &1534925206 +--- !u!1 &1176403628 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1717,131 +2098,1167 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1534925207} - - component: {fileID: 1534925210} - - component: {fileID: 1534925209} - - component: {fileID: 1534925208} + - component: {fileID: 1176403629} + - component: {fileID: 1176403631} + - component: {fileID: 1176403630} m_Layer: 5 - m_Name: Button Update trackable + m_Name: Headline m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1534925207 +--- !u!224 &1176403629 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1534925206} + m_GameObject: {fileID: 1176403628} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.001, y: 0.001, z: 0.001} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 1650656169} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0.02} + m_SizeDelta: {x: 250, y: 25} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1176403630 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1176403628} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: AR World Anchor + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 1 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1176403631 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1176403628} + m_CullTransparentMesh: 1 +--- !u!1 &1270536908 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1270536909} + - component: {fileID: 1270536911} + - component: {fileID: 1270536910} + m_Layer: 5 + m_Name: Server + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1270536909 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1270536908} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 1 - m_Children: - - {fileID: 1864481863} + m_ConstrainProportionsScale: 0 + m_Children: [] m_Father: {fileID: 491226576} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 80} + m_SizeDelta: {x: 0, y: 100} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1534925208 +--- !u!114 &1270536910 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1534925206} + m_GameObject: {fileID: 1270536908} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} m_Name: m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 1 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 1534925209} - m_OnClick: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 2123268211} - m_TargetAssemblyTypeName: OpenAPITest, Assembly-CSharp - m_MethodName: OnButtonClick_UpdateLastTrackable - m_Mode: 1 - m_Arguments: - m_ObjectArgument: {fileID: 0} - m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 0 - m_FloatArgument: 0 - m_StringArgument: - m_BoolArgument: 0 - m_CallState: 2 ---- !u!114 &1534925209 -MonoBehaviour: + m_Calls: [] + m_text: 'ARF Server: -' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 36 + m_fontSizeBase: 36 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 1 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1270536911 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1270536908} + m_CullTransparentMesh: 1 +--- !u!1 &1371016666 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1371016667} + - component: {fileID: 1371016669} + - component: {fileID: 1371016668} + m_Layer: 5 + m_Name: Headline + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1371016667 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371016666} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.001, y: 0.001, z: 0.001} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 1564988513} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0.02} + m_SizeDelta: {x: 250, y: 25} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1371016668 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371016666} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: AR Trackable + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 1 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1371016669 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1371016666} + m_CullTransparentMesh: 1 +--- !u!1 &1534925206 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1534925207} + - component: {fileID: 1534925210} + - component: {fileID: 1534925209} + - component: {fileID: 1534925208} + m_Layer: 5 + m_Name: Button Update trackable + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1534925207 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1534925206} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 1864481863} + m_Father: {fileID: 491226576} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 80} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1534925208 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1534925206} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1534925209} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2123268211} + m_TargetAssemblyTypeName: OpenAPITest, Assembly-CSharp + m_MethodName: OnButtonClick_UpdateLastTrackable + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &1534925209 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1534925206} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 0.25 +--- !u!222 &1534925210 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1534925206} + m_CullTransparentMesh: 1 +--- !u!1 &1564988512 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1564988513} + - component: {fileID: 1564988516} + - component: {fileID: 1564988515} + - component: {fileID: 1564988514} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1564988513 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1564988512} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1371016667} + - {fileID: 2028750463} + m_Father: {fileID: 1035254689} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0.1263, y: -0.1} + m_SizeDelta: {x: 640, y: 480} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1564988514 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1564988512} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1564988515 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1564988512} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 1 +--- !u!223 &1564988516 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1564988512} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 2 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 + m_AdditionalShaderChannelsFlag: 25 + m_UpdateRectTransformForStandalone: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!1 &1580568509 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1580568510} + - component: {fileID: 1580568513} + - component: {fileID: 1580568512} + - component: {fileID: 1580568511} + m_Layer: 0 + m_Name: X + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1580568510 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1580568509} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: 0.7071068, w: 0.7071068} + m_LocalPosition: {x: 0.1, y: 0, z: 0} + m_LocalScale: {x: 0.019999998, y: 0.05000001, z: 0.020000001} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 976672958} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 90} +--- !u!136 &1580568511 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1580568509} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &1580568512 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1580568509} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0c6a9f85031693343a9e37c4a08627e9, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1580568513 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1580568509} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1614791895 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1614791896} + - component: {fileID: 1614791899} + - component: {fileID: 1614791898} + - component: {fileID: 1614791897} + m_Layer: 0 + m_Name: Z + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1614791896 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1614791895} + serializedVersion: 2 + m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 0, z: 0.1} + m_LocalScale: {x: 0.020000001, y: 0.05000001, z: 0.019999998} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 976672958} + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!136 &1614791897 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1614791895} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &1614791898 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1614791895} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1b6b868784cd25c46a90fe7b882fddb2, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1614791899 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1614791895} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1650656168 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1650656169} + - component: {fileID: 1650656172} + - component: {fileID: 1650656171} + - component: {fileID: 1650656170} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1650656169 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1650656168} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1176403629} + - {fileID: 1087987907} + m_Father: {fileID: 181827839} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0.1263, y: -0.1} + m_SizeDelta: {x: 640, y: 480} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1650656170 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1650656168} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1650656171 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1650656168} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 1 +--- !u!223 &1650656172 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1650656168} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 2 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 + m_AdditionalShaderChannelsFlag: 25 + m_UpdateRectTransformForStandalone: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!1 &1685018302 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1685018303} + - component: {fileID: 1685018306} + - component: {fileID: 1685018305} + - component: {fileID: 1685018304} + m_Layer: 0 + m_Name: Z + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1685018303 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1685018302} + serializedVersion: 2 + m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 0, z: 0.1} + m_LocalScale: {x: 0.020000001, y: 0.05000001, z: 0.019999998} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 313423862} + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!136 &1685018304 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1685018302} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &1685018305 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1685018302} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1b6b868784cd25c46a90fe7b882fddb2, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1685018306 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1685018302} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1802205026 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1802205027} + - component: {fileID: 1802205030} + - component: {fileID: 1802205029} + - component: {fileID: 1802205028} + m_Layer: 0 + m_Name: Y + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1802205027 +Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1534925206} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: + m_GameObject: {fileID: 1802205026} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0.1, z: 0} + m_LocalScale: {x: 0.020000001, y: 0.05, z: 0.020000001} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 976672958} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!136 &1802205028 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1802205026} m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 0.25 ---- !u!222 &1534925210 -CanvasRenderer: + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &1802205029 +MeshRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1534925206} - m_CullTransparentMesh: 1 + m_GameObject: {fileID: 1802205026} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 19de5bd9483daf448a5fab21d3eecba3, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1802205030 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1802205026} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} --- !u!1 &1809658683 GameObject: m_ObjectHideFlags: 0 @@ -2110,6 +3527,113 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1864481862} m_CullTransparentMesh: 1 +--- !u!1 &1877813049 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1877813050} + - component: {fileID: 1877813053} + - component: {fileID: 1877813052} + - component: {fileID: 1877813051} + m_Layer: 0 + m_Name: X + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1877813050 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1877813049} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: 0.7071068, w: 0.7071068} + m_LocalPosition: {x: 0.1, y: 0, z: 0} + m_LocalScale: {x: 0.019999998, y: 0.05000001, z: 0.020000001} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 313423862} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 90} +--- !u!136 &1877813051 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1877813049} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &1877813052 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1877813049} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0c6a9f85031693343a9e37c4a08627e9, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1877813053 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1877813049} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} --- !u!1 &1900725046 GameObject: m_ObjectHideFlags: 0 @@ -2563,6 +4087,142 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1996377110} m_CullTransparentMesh: 1 +--- !u!1 &2028750462 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2028750463} + - component: {fileID: 2028750465} + - component: {fileID: 2028750464} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2028750463 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2028750462} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.001, y: 0.001, z: 0.001} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 1564988513} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -0.025} + m_SizeDelta: {x: 250, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2028750464 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2028750462} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: 'Name: Default Trackable 111 + + UUID: 80153adf-b32c-4f77-a374-b20a92c822d1' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 16 + m_fontSizeBase: 16 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &2028750465 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2028750462} + m_CullTransparentMesh: 1 --- !u!1 &2040736466 GameObject: m_ObjectHideFlags: 0 @@ -2765,6 +4425,113 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2095380537} m_CullTransparentMesh: 1 +--- !u!1 &2116690939 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2116690940} + - component: {fileID: 2116690943} + - component: {fileID: 2116690942} + - component: {fileID: 2116690941} + m_Layer: 0 + m_Name: Y + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2116690940 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2116690939} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0.1, z: 0} + m_LocalScale: {x: 0.020000001, y: 0.05, z: 0.020000001} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 313423862} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!136 &2116690941 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2116690939} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &2116690942 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2116690939} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 19de5bd9483daf448a5fab21d3eecba3, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &2116690943 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2116690939} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} --- !u!1 &2123268210 GameObject: m_ObjectHideFlags: 0 @@ -2794,7 +4561,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 8d8b78014fb03e94c90db2fa1a2fde7b, type: 3} m_Name: m_EditorClassIdentifier: - server: {fileID: 11400000, guid: a3bbdc2753015174d9cf466761005897, type: 2} + server: {fileID: 11400000, guid: db0064cecabb1b244a4e158d43602781, type: 2} servername: {fileID: 1270536910} output: {fileID: 1973593797} --- !u!4 &2123268212 @@ -2821,3 +4588,4 @@ SceneRoots: - {fileID: 2040736469} - {fileID: 2123268212} - {fileID: 846631106} + - {fileID: 1006052647} diff --git a/Runtime/Scripts/REST/TrackableRequest.cs b/Runtime/Scripts/REST/TrackableRequest.cs index 73f5fe3..cd65c94 100644 --- a/Runtime/Scripts/REST/TrackableRequest.cs +++ b/Runtime/Scripts/REST/TrackableRequest.cs @@ -66,9 +66,9 @@ namespace ETSI.ARF.WorldStorage.REST Debug.Log("[REST] Create 1 Trackable..."); // Add some management stuffs - trackable.UUID = Guid.NewGuid(); - trackable.CreatorUUID = Guid.Empty; - + if (trackable.UUID == Guid.Empty) trackable.UUID = Guid.NewGuid(); + if (trackable.CreatorUUID == Guid.Empty) trackable.CreatorUUID = System.Guid.Parse("8fb169e2-8910-4cd5-a8f9-b7abff38d013"); + ResponseObject ro = new ResponseObject("Create Trackable " + trackable.Name + " (no UUID)", func); apiClient.AddTrackableAsync(token, trackable, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; diff --git a/Runtime/Scripts/REST/WorldAnchorRequest.cs b/Runtime/Scripts/REST/WorldAnchorRequest.cs index 7ed1418..1c19e53 100644 --- a/Runtime/Scripts/REST/WorldAnchorRequest.cs +++ b/Runtime/Scripts/REST/WorldAnchorRequest.cs @@ -67,8 +67,8 @@ namespace ETSI.ARF.WorldStorage.REST Debug.Log("[REST] Create 1 WorldAnchor..."); // Add some management stuffs - worldAnchor.UUID = Guid.NewGuid(); - worldAnchor.CreatorUUID = Guid.Empty; + if (worldAnchor.UUID == Guid.Empty) worldAnchor.UUID = Guid.NewGuid(); + if (worldAnchor.CreatorUUID == Guid.Empty) worldAnchor.CreatorUUID = System.Guid.Parse("8fb169e2-8910-4cd5-a8f9-b7abff38d013"); ResponseObject ro = new ResponseObject("Create WorldAnchor " + worldAnchor.Name + " (no UUID)", func); apiClient.AddWorldAnchorAsync(token, worldAnchor, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); diff --git a/Runtime/Scripts/REST/WorldLinkRequest.cs b/Runtime/Scripts/REST/WorldLinkRequest.cs index 2ea9ef3..e7be11e 100644 --- a/Runtime/Scripts/REST/WorldLinkRequest.cs +++ b/Runtime/Scripts/REST/WorldLinkRequest.cs @@ -66,8 +66,8 @@ namespace ETSI.ARF.WorldStorage.REST Debug.Log("[REST] Create 1 WorldLink..."); // Add some management stuffs - worldLink.UUID = Guid.NewGuid(); - worldLink.CreatorUUID = Guid.Empty; + if (worldLink.UUID == Guid.Empty) worldLink.UUID = Guid.NewGuid(); + if (worldLink.CreatorUUID == Guid.Empty) worldLink.CreatorUUID = System.Guid.Parse("8fb169e2-8910-4cd5-a8f9-b7abff38d013"); ResponseObject ro = new ResponseObject("Create WorldLink (no UUID)", func); apiClient.AddWorldLinkAsync(token, worldLink, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); -- GitLab From 5e91e32387700c0c852878e84c2098af794d2ac7 Mon Sep 17 00:00:00 2001 From: jlacoche Date: Sat, 13 Jul 2024 00:53:58 +0200 Subject: [PATCH 05/13] add sync methods for trackables world anchors and links request --- Runtime/Scripts/REST/TrackableRequest.cs | 10 ++++++++++ Runtime/Scripts/REST/WorldAnchorRequest.cs | 9 +++++++++ Runtime/Scripts/REST/WorldLinkRequest.cs | 9 +++++++++ 3 files changed, 28 insertions(+) diff --git a/Runtime/Scripts/REST/TrackableRequest.cs b/Runtime/Scripts/REST/TrackableRequest.cs index cd65c94..044ea21 100644 --- a/Runtime/Scripts/REST/TrackableRequest.cs +++ b/Runtime/Scripts/REST/TrackableRequest.cs @@ -45,6 +45,16 @@ namespace ETSI.ARF.WorldStorage.REST return ro; } + static public List GetTrackablesSync(WorldStorageServer ws) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log("[REST] Request Trackables..."); + return apiClient.GetTrackables(token); + } + static public ResponseObject> GetTrackablesAsync(WorldStorageServer ws, Action>> func) { wsServer = ws; diff --git a/Runtime/Scripts/REST/WorldAnchorRequest.cs b/Runtime/Scripts/REST/WorldAnchorRequest.cs index 1c19e53..34ba629 100644 --- a/Runtime/Scripts/REST/WorldAnchorRequest.cs +++ b/Runtime/Scripts/REST/WorldAnchorRequest.cs @@ -46,6 +46,15 @@ namespace ETSI.ARF.WorldStorage.REST return ro; } + static public List GetWorldAnchorsSync(WorldStorageServer ws) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + return apiClient.GetWorldAnchors(token); + } + static public ResponseObject> GetWorldAnchorsAsync(WorldStorageServer ws, Action>> func) { wsServer = ws; diff --git a/Runtime/Scripts/REST/WorldLinkRequest.cs b/Runtime/Scripts/REST/WorldLinkRequest.cs index e7be11e..7350dde 100644 --- a/Runtime/Scripts/REST/WorldLinkRequest.cs +++ b/Runtime/Scripts/REST/WorldLinkRequest.cs @@ -45,6 +45,15 @@ namespace ETSI.ARF.WorldStorage.REST return ro; } + static public List GetWorldLinksSync(WorldStorageServer ws) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + return apiClient.GetWorldLinks(token); + } + static public ResponseObject> GetWorldLinksAsync(WorldStorageServer ws, Action>> func) { wsServer = ws; -- GitLab From f36b78ff890f2da8102278aedaea4ba595c4be75 Mon Sep 17 00:00:00 2001 From: Stephane Louis Dit Picard Date: Tue, 16 Jul 2024 18:00:11 +0200 Subject: [PATCH 06/13] refactor: add missing sync methods for trackables, world anchors and links requests --- Runtime/Scripts/REST/AdminRequest.cs | 30 ++++++++-- .../REST/RelocalizationInformationRequest.cs | 11 +++- Runtime/Scripts/REST/TrackableRequest.cs | 55 +++++++++++++++++-- Runtime/Scripts/REST/WorldAnchorRequest.cs | 55 +++++++++++++++++-- Runtime/Scripts/REST/WorldLinkRequest.cs | 55 +++++++++++++++++-- 5 files changed, 183 insertions(+), 23 deletions(-) diff --git a/Runtime/Scripts/REST/AdminRequest.cs b/Runtime/Scripts/REST/AdminRequest.cs index cf2304b..4ab8496 100644 --- a/Runtime/Scripts/REST/AdminRequest.cs +++ b/Runtime/Scripts/REST/AdminRequest.cs @@ -32,10 +32,10 @@ namespace ETSI.ARF.WorldStorage.REST // // Wrapper for the endpoints // - static private string Ping(WorldStorageServer ws) + static public string PingSync(WorldStorageServer ws) { wsServer = ws; - var httpClient = new UnityWebRequestHttpClient(ws.URI); + var httpClient = new BasicHTTPClient(ws.URI); apiClient = new WorldStorageClient(httpClient); string response = apiClient.GetPing(); @@ -50,10 +50,20 @@ namespace ETSI.ARF.WorldStorage.REST Debug.Log("[REST] Request Ping..."); ResponseObject ro = new ResponseObject("Request Ping", func); - apiClient.GetPingAsync().ContinueWith(OnReceiveObject, ro); + apiClient.GetPingAsync(ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } + static public string AdminSync(WorldStorageServer ws) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + string response = apiClient.GetAdmin(); + return response; + } + static public ResponseObject AdminAsync(WorldStorageServer ws, Action> func) { wsServer = ws; @@ -62,10 +72,20 @@ namespace ETSI.ARF.WorldStorage.REST Debug.Log("[REST] Request Admin..."); ResponseObject ro = new ResponseObject("Request Admin", func); - apiClient.GetAdminAsync().ContinueWith(OnReceiveObject, ro); + apiClient.GetAdminAsync(ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } + static public string VersionSync(WorldStorageServer ws) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + string response = apiClient.GetVersion(); + return response; + } + static public ResponseObject VersionAsync(WorldStorageServer ws, Action> func) { wsServer = ws; @@ -74,7 +94,7 @@ namespace ETSI.ARF.WorldStorage.REST Debug.Log("[REST] Request Version..."); ResponseObject ro = new ResponseObject("Request Version", func); - apiClient.GetVersionAsync().ContinueWith(OnReceiveObject, ro); + apiClient.GetVersionAsync(ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } } diff --git a/Runtime/Scripts/REST/RelocalizationInformationRequest.cs b/Runtime/Scripts/REST/RelocalizationInformationRequest.cs index 309618c..95470c6 100644 --- a/Runtime/Scripts/REST/RelocalizationInformationRequest.cs +++ b/Runtime/Scripts/REST/RelocalizationInformationRequest.cs @@ -32,7 +32,7 @@ namespace ETSI.ARF.WorldStorage.REST { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); - apiClient = new WorldStorageClient(httpClient); + apiClient = new MyWorldStorageClient(httpClient); ResponseObject ro = new ResponseObject("Request Reloc Information ", func); @@ -45,12 +45,16 @@ namespace ETSI.ARF.WorldStorage.REST newOne.Mode = modes[i]; anonymous.Add(newOne); } - apiClient.GetRelocalizationInformationAsync(token, anonymous, capabilities).ContinueWith(OnReceiveObject, ro); + apiClient.GetRelocalizationInformationAsync(token, anonymous, capabilities, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } - static public Response GetRelocalizationInformation(WorldStorageServer ws, List uuids, List modes, List capabilities) + { + return GetRelocalizationInformationSync(ws, uuids, modes, capabilities); + } + + static public Response GetRelocalizationInformationSync(WorldStorageServer ws, List uuids, List modes, List capabilities) { wsServer = ws; var httpClient = new BasicHTTPClient(ws.URI); @@ -102,6 +106,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage } } + // Custom client to be able to properly serialize objects in the query string public partial class MyWorldStorageClient : WorldStorageClient { public MyWorldStorageClient(IHttpClient httpClient) : base(httpClient) diff --git a/Runtime/Scripts/REST/TrackableRequest.cs b/Runtime/Scripts/REST/TrackableRequest.cs index 044ea21..9aa9adf 100644 --- a/Runtime/Scripts/REST/TrackableRequest.cs +++ b/Runtime/Scripts/REST/TrackableRequest.cs @@ -33,13 +33,23 @@ namespace ETSI.ARF.WorldStorage.REST // // Wrapper for the endpoints // + static public Trackable GetTrackableSync(WorldStorageServer ws, Guid UUID) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log($"[REST] Request Trackable {UUID}..."); + return apiClient.GetTrackableById(token, UUID); + } + static public ResponseObject GetTrackableAsync(WorldStorageServer ws, Guid UUID, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("[REST] Request 1 Trackable..."); + Debug.Log($"[REST] Request Trackable {UUID}..."); ResponseObject ro = new ResponseObject("Request Trackable " + UUID.ToString(), func); apiClient.GetTrackableByIdAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; @@ -67,41 +77,76 @@ namespace ETSI.ARF.WorldStorage.REST return ro; } + static public string CreateTrackableSync(WorldStorageServer ws, Trackable trackable) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + // Add some management stuffs + if (trackable.UUID == Guid.Empty) trackable.UUID = Guid.NewGuid(); + if (trackable.CreatorUUID == Guid.Empty) trackable.CreatorUUID = System.Guid.Parse("8fb169e2-8910-4cd5-a8f9-b7abff38d013"); + + Debug.Log($"[REST] Create Trackable {trackable.UUID}..."); + return apiClient.AddTrackable(token, trackable); + } + static public ResponseObject CreateTrackableAsync(WorldStorageServer ws, Trackable trackable, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("[REST] Create 1 Trackable..."); - // Add some management stuffs if (trackable.UUID == Guid.Empty) trackable.UUID = Guid.NewGuid(); if (trackable.CreatorUUID == Guid.Empty) trackable.CreatorUUID = System.Guid.Parse("8fb169e2-8910-4cd5-a8f9-b7abff38d013"); + Debug.Log($"[REST] Create Trackable {trackable.UUID}..."); + ResponseObject ro = new ResponseObject("Create Trackable " + trackable.Name + " (no UUID)", func); apiClient.AddTrackableAsync(token, trackable, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } + static public string UpdateTrackableSync(WorldStorageServer ws, Trackable trackable) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log($"[REST] Update Trackable {trackable.UUID}..."); + return apiClient.ModifyTrackable(token, trackable); + } + static public ResponseObject UpdateTrackableAsync(WorldStorageServer ws, Trackable trackable, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("[REST] Update Trackable..."); + Debug.Log($"[REST] Update Trackable {trackable.UUID}..."); ResponseObject ro = new ResponseObject("Update Trackable " + trackable.UUID.ToString(), func); apiClient.ModifyTrackableAsync(token, trackable,ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } + + static public string DeleteTrackableSync(WorldStorageServer ws, Guid UUID) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log($"[REST] Delete Trackable {UUID}..."); + return apiClient.DeleteTrackable(token, UUID); + } + static public ResponseObject DeleteTrackableAsync(WorldStorageServer ws, Guid UUID, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("[REST] Delete 1 Trackable..."); + Debug.Log($"[REST] Delete Trackable {UUID}..."); ResponseObject ro = new ResponseObject("Delete Trackable " + UUID.ToString(), func); apiClient.DeleteTrackableAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; diff --git a/Runtime/Scripts/REST/WorldAnchorRequest.cs b/Runtime/Scripts/REST/WorldAnchorRequest.cs index 34ba629..d6b2c95 100644 --- a/Runtime/Scripts/REST/WorldAnchorRequest.cs +++ b/Runtime/Scripts/REST/WorldAnchorRequest.cs @@ -34,13 +34,23 @@ namespace ETSI.ARF.WorldStorage.REST // // Wrapper for the endpoints // + static public WorldAnchor GetWorldAnchorSync(WorldStorageServer ws, Guid UUID) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log($"[REST] Request WorldAnchor {UUID}..."); + return apiClient.GetWorldAnchorById(token, UUID); + } + static public ResponseObject GetWorldAnchorAsync(WorldStorageServer ws, Guid UUID, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("[REST] Request 1 WorldAnchor..."); + Debug.Log($"[REST] Request WorldAnchor {UUID}..."); ResponseObject ro = new ResponseObject("Request WorldAnchor " + UUID.ToString(), func); apiClient.GetWorldAnchorByIdAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; @@ -52,6 +62,7 @@ namespace ETSI.ARF.WorldStorage.REST var httpClient = new BasicHTTPClient(ws.URI); apiClient = new WorldStorageClient(httpClient); + Debug.Log("[REST] Request WorldAnchors..."); return apiClient.GetWorldAnchors(token); } @@ -67,41 +78,75 @@ namespace ETSI.ARF.WorldStorage.REST return ro; } + static public string CreateWorldAnchorSync(WorldStorageServer ws, WorldAnchor worldAnchor) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + // Add some management stuffs + if (worldAnchor.UUID == Guid.Empty) worldAnchor.UUID = Guid.NewGuid(); + if (worldAnchor.CreatorUUID == Guid.Empty) worldAnchor.CreatorUUID = System.Guid.Parse("8fb169e2-8910-4cd5-a8f9-b7abff38d013"); + + Debug.Log($"[REST] Create WorldAnchor {worldAnchor.UUID}..."); + return apiClient.AddWorldAnchor(token, worldAnchor); + } + static public ResponseObject CreateWorldAnchorAsync(WorldStorageServer ws, WorldAnchor worldAnchor, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("[REST] Create 1 WorldAnchor..."); - // Add some management stuffs if (worldAnchor.UUID == Guid.Empty) worldAnchor.UUID = Guid.NewGuid(); if (worldAnchor.CreatorUUID == Guid.Empty) worldAnchor.CreatorUUID = System.Guid.Parse("8fb169e2-8910-4cd5-a8f9-b7abff38d013"); + Debug.Log($"[REST] Create WorldAnchor {worldAnchor.UUID}..."); ResponseObject ro = new ResponseObject("Create WorldAnchor " + worldAnchor.Name + " (no UUID)", func); apiClient.AddWorldAnchorAsync(token, worldAnchor, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } + static public string UpdateWorldAnchorSync(WorldStorageServer ws, WorldAnchor worldAnchor) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log($"[REST] Update WorldAnchor {worldAnchor.UUID}..."); + return apiClient.ModifyWorldAnchor(token, worldAnchor); + } + static public ResponseObject UpdateWorldAnchorAsync(WorldStorageServer ws, WorldAnchor worldAnchor, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("[REST] Update WorldAnchor..."); + Debug.Log($"[REST] Update WorldAnchor {worldAnchor.UUID}..."); ResponseObject ro = new ResponseObject("Update WorldAnchor " + worldAnchor.UUID.ToString(), func); apiClient.ModifyWorldAnchorAsync(token, worldAnchor, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } + + static public string DeleteWorldAnchorSync(WorldStorageServer ws, Guid UUID) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log($"[REST] Delete WorldAnchor {UUID}..."); + return apiClient.DeleteWorldAnchor(token, UUID); + } + static public ResponseObject DeleteWorldAnchorAsync(WorldStorageServer ws, Guid UUID, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("[REST] Delete 1 WorldAnchor..."); + Debug.Log($"[REST] Delete WorldAnchor {UUID}..."); ResponseObject ro = new ResponseObject("Delete WorldAnchor " + UUID.ToString(), func); apiClient.DeleteWorldAnchorAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; diff --git a/Runtime/Scripts/REST/WorldLinkRequest.cs b/Runtime/Scripts/REST/WorldLinkRequest.cs index 7350dde..44b489f 100644 --- a/Runtime/Scripts/REST/WorldLinkRequest.cs +++ b/Runtime/Scripts/REST/WorldLinkRequest.cs @@ -33,13 +33,23 @@ namespace ETSI.ARF.WorldStorage.REST // // Wrapper for the endpoints // + static public WorldLink GetWorldLinkSync(WorldStorageServer ws, Guid UUID) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log($"[REST] Request WorldLink {UUID}..."); + return apiClient.GetWorldLinkById(token, UUID); + } + static public ResponseObject GetWorldLinkAsync(WorldStorageServer ws, Guid UUID, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("[REST] Request 1 WorldLink..."); + Debug.Log($"[REST] Request WorldLink {UUID}..."); ResponseObject ro = new ResponseObject("Request WorldLink " + UUID.ToString(), func); apiClient.GetWorldLinkByIdAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; @@ -51,6 +61,7 @@ namespace ETSI.ARF.WorldStorage.REST var httpClient = new BasicHTTPClient(ws.URI); apiClient = new WorldStorageClient(httpClient); + Debug.Log("[REST] Request WorldLinks..."); return apiClient.GetWorldLinks(token); } @@ -66,41 +77,75 @@ namespace ETSI.ARF.WorldStorage.REST return ro; } + static public string CreateWorldLinkSync(WorldStorageServer ws, WorldLink worldLink) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + // Add some management stuffs + if (worldLink.UUID == Guid.Empty) worldLink.UUID = Guid.NewGuid(); + if (worldLink.CreatorUUID == Guid.Empty) worldLink.CreatorUUID = System.Guid.Parse("8fb169e2-8910-4cd5-a8f9-b7abff38d013"); + + Debug.Log($"[REST] Create WorldLink {worldLink.UUID}..."); + return apiClient.AddWorldLink(token, worldLink); + } + static public ResponseObject CreateWorldLinkAsync(WorldStorageServer ws, WorldLink worldLink, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("[REST] Create 1 WorldLink..."); - // Add some management stuffs if (worldLink.UUID == Guid.Empty) worldLink.UUID = Guid.NewGuid(); if (worldLink.CreatorUUID == Guid.Empty) worldLink.CreatorUUID = System.Guid.Parse("8fb169e2-8910-4cd5-a8f9-b7abff38d013"); + Debug.Log($"[REST] Create WorldLink {worldLink.UUID}..."); ResponseObject ro = new ResponseObject("Create WorldLink (no UUID)", func); apiClient.AddWorldLinkAsync(token, worldLink, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } + static public string UpdateWorldLinkSync(WorldStorageServer ws, WorldLink worldLink) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log($"[REST] Update WorldLink {worldLink.UUID}..."); + return apiClient.ModifyWorldLink(token, worldLink); + } + static public ResponseObject UpdateWorldLinkAsync(WorldStorageServer ws, WorldLink worldLink, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("[REST] Update WorldLink..."); + Debug.Log($"[REST] Update WorldLink {worldLink.UUID}..."); ResponseObject ro = new ResponseObject("Update WorldLink " + worldLink.UUID.ToString(), func); apiClient.ModifyWorldLinkAsync(token, worldLink, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } + + static public string DeleteWorldLinkSync(WorldStorageServer ws, Guid UUID) + { + wsServer = ws; + var httpClient = new BasicHTTPClient(ws.URI); + apiClient = new WorldStorageClient(httpClient); + + Debug.Log($"[REST] Delete WorldLink {UUID}..."); + return apiClient.DeleteWorldLink(token, UUID); + } + static public ResponseObject DeleteWorldLinkAsync(WorldStorageServer ws, Guid UUID, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - Debug.Log("[REST] Delete 1 WorldLink..."); + Debug.Log($"[REST] Delete WorldLink {UUID}..."); ResponseObject ro = new ResponseObject("Delete WorldLink " + UUID.ToString(), func); apiClient.DeleteWorldLinkAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; -- GitLab From 63adf7f5487d843f031a15c4db1d493fefe95a31 Mon Sep 17 00:00:00 2001 From: Stephane Louis Dit Picard Date: Wed, 17 Jul 2024 12:47:42 +0200 Subject: [PATCH 07/13] feat: add custom editors for server and user --- Editor/Scripts/WorldStorageServerEditor.cs | 173 ++++++++++++++++++ .../Scripts/WorldStorageServerEditor.cs.meta | 11 ++ Editor/Scripts/WorldStorageUserEditor.cs | 51 ++++++ Editor/Scripts/WorldStorageUserEditor.cs.meta | 11 ++ 4 files changed, 246 insertions(+) create mode 100644 Editor/Scripts/WorldStorageServerEditor.cs create mode 100644 Editor/Scripts/WorldStorageServerEditor.cs.meta create mode 100644 Editor/Scripts/WorldStorageUserEditor.cs create mode 100644 Editor/Scripts/WorldStorageUserEditor.cs.meta diff --git a/Editor/Scripts/WorldStorageServerEditor.cs b/Editor/Scripts/WorldStorageServerEditor.cs new file mode 100644 index 0000000..7cbc404 --- /dev/null +++ b/Editor/Scripts/WorldStorageServerEditor.cs @@ -0,0 +1,173 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2024 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: July 2024 +// + +using System.Collections; +using UnityEngine; +using UnityEditor; + +using ETSI.ARF.OpenAPI; +using ETSI.ARF.WorldStorage; +using ETSI.ARF.WorldStorage.REST; + +[CustomEditor(typeof(WorldStorageServer))] +public class WorldStorageServerEditor : Editor +{ + WorldStorageServer server; + + private string state = ""; + private string version = ""; + + private string test = ""; + + private Queue handleResponseQueue = new Queue(); + + private ResponseObject pendingTest = null; + private ResponseObject pendingState = null; + private ResponseObject pendingVersion = null; + + public void OnEnable() + { + server = (WorldStorageServer)target; + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + DrawDefaultInspector(); + EditorGUILayout.Space(); + + if (GUILayout.Button("Test server")) + { + TestPing(); + } + EditorGUILayout.LabelField("Test Response", test); + + EditorGUILayout.Space(); + + if (GUILayout.Button("Query server")) + { + QueryServer(); + } + + EditorGUILayout.LabelField("Server State", state); + EditorGUILayout.LabelField("OpenAPI Version", version); + + if (handleResponseQueue.Count > 0) + { + object o = handleResponseQueue.Dequeue(); + if (o.Equals(pendingTest)) + { + ResponseObject response = o as ResponseObject; + Debug.Log($"Get '{response.result}' from server"); + + test = response.result; + pendingTest = null; + EditorUtility.SetDirty(target); + } + else if (o.Equals(pendingState)) + { + ResponseObject response = o as ResponseObject; + Debug.Log($"Get '{response.result}' from server"); + + state = response.result; + pendingState = null; + EditorUtility.SetDirty(target); + } + else if (o.Equals(pendingVersion)) + { + ResponseObject response = o as ResponseObject; + Debug.Log($"Get '{response.result}' from server"); + + version = response.result; + pendingVersion = null; + EditorUtility.SetDirty(target); + } + else + { + Debug.Log("Unsupported response!"); + } + } + } + + public override bool RequiresConstantRepaint() + { + return handleResponseQueue.Count > 0; + } + + void OnSceneGUI() + { + Debug.Log("OnSceneGUI"); + } + + private void TestPing() + { + test = ""; + EditorUtility.SetDirty(target); + + if (server == null) + { + Debug.LogError("No server defined!"); + return; + } + + //string response = AdminRequest.PingSync(server); + //EditorUtility.DisplayDialog("Test Server", $"Get '{response}' from server", "OK"); + + if (pendingTest != null) + { + pendingTest.Cancel(); + } + + pendingTest = AdminRequest.PingAsync(server, (response) => + { + handleResponseQueue.Enqueue(response); + Debug.Log($"Request Time: { response.requestTime.ToLongTimeString() } / Total Time: { response.DeltaTime.TotalMilliseconds }ms\n\nContent:\n{ response.result }"); + }); + + Debug.Log("Starting request @ time: " + pendingTest.requestTime.ToLongTimeString() + "..."); + } + + private void QueryServer() + { + version = ""; + state = ""; + + if (pendingState != null) + { + pendingState.Cancel(); + } + + pendingState = AdminRequest.AdminAsync(server, (response) => + { + handleResponseQueue.Enqueue(response); + }); + + if (pendingVersion != null) + { + pendingVersion.Cancel(); + } + + pendingVersion = AdminRequest.VersionAsync(server, (response) => + { + handleResponseQueue.Enqueue(response); + }); + } +} \ No newline at end of file diff --git a/Editor/Scripts/WorldStorageServerEditor.cs.meta b/Editor/Scripts/WorldStorageServerEditor.cs.meta new file mode 100644 index 0000000..058d2a8 --- /dev/null +++ b/Editor/Scripts/WorldStorageServerEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e5c9b5bdbeaab49729133f4ac17ded99 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/WorldStorageUserEditor.cs b/Editor/Scripts/WorldStorageUserEditor.cs new file mode 100644 index 0000000..7de785f --- /dev/null +++ b/Editor/Scripts/WorldStorageUserEditor.cs @@ -0,0 +1,51 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2022 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: June 2022 +// + +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +using ETSI.ARF.WorldStorage; + +[CustomEditor(typeof(WorldStorageUser))] +public class WorldStorageUserEditor : Editor +{ + WorldStorageUser user; + + public void OnEnable() + { + user = (WorldStorageUser)target; + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + DrawDefaultInspector(); + EditorGUILayout.Space(); + + if (GUILayout.Button("Generate New Creator UUID")) + { + user.UUID = System.Guid.NewGuid().ToString(); + EditorUtility.SetDirty(target); + } + } +} diff --git a/Editor/Scripts/WorldStorageUserEditor.cs.meta b/Editor/Scripts/WorldStorageUserEditor.cs.meta new file mode 100644 index 0000000..0efd092 --- /dev/null +++ b/Editor/Scripts/WorldStorageUserEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 27356e11ca7a946a6a6cf289f784ee18 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: -- GitLab From cd1fe3c66370796bccb3b1ad842000044e14888f Mon Sep 17 00:00:00 2001 From: jlacoche Date: Mon, 29 Jul 2024 11:13:59 +0200 Subject: [PATCH 08/13] Include all files related to editor --- Editor/Images.meta | 12 + Editor/Images/anchor.png | Bin 0 -> 21219 bytes Editor/Images/anchor.png.meta | 98 ++ Editor/Images/cloud.png | Bin 0 -> 31613 bytes Editor/Images/cloud.png.meta | 98 ++ Editor/Images/link.png | Bin 0 -> 18903 bytes Editor/Images/link.png.meta | 98 ++ Editor/Images/trackable.png | Bin 0 -> 14290 bytes Editor/Images/trackable.png.meta | 98 ++ Editor/Images/warning.png | Bin 0 -> 55016 bytes Editor/Images/warning.png.meta | 98 ++ Editor/Materials.meta | 8 + Editor/Materials/anchor.mat | 80 ++ Editor/Materials/anchor.mat.meta | 8 + Editor/Materials/blue.mat | 80 ++ Editor/Materials/blue.mat.meta | 8 + Editor/Materials/green.mat | 80 ++ Editor/Materials/green.mat.meta | 8 + Editor/Materials/link.mat | 80 ++ Editor/Materials/link.mat.meta | 8 + Editor/Materials/red.mat | 80 ++ Editor/Materials/red.mat.meta | 8 + Editor/Materials/trackable.mat | 80 ++ Editor/Materials/trackable.mat.meta | 8 + Editor/Scripts/Graph.meta | 8 + Editor/Scripts/Graph/ARFEdgeLink.cs | 84 ++ Editor/Scripts/Graph/ARFEdgeLink.cs.meta | 11 + Editor/Scripts/Graph/ARFGraphView.cs | 684 +++++++++ Editor/Scripts/Graph/ARFGraphView.cs.meta | 11 + Editor/Scripts/Graph/ARFNode.cs | 140 ++ Editor/Scripts/Graph/ARFNode.cs.meta | 11 + Editor/Scripts/Graph/ARFNodeTrackable.cs | 85 ++ Editor/Scripts/Graph/ARFNodeTrackable.cs.meta | 11 + Editor/Scripts/Graph/ARFNodeWorldAnchor.cs | 79 + .../Scripts/Graph/ARFNodeWorldAnchor.cs.meta | 11 + Editor/Scripts/Graph/ARFPort.cs | 80 ++ Editor/Scripts/Graph/ARFPort.cs.meta | 11 + Editor/Scripts/Graph/WorldLinkListener.cs | 98 ++ .../Scripts/Graph/WorldLinkListener.cs.meta | 11 + Editor/Scripts/Windows.meta | 8 + Editor/Scripts/Windows/BaseWindow.cs | 118 ++ Editor/Scripts/Windows/BaseWindow.cs.meta | 14 + Editor/Scripts/Windows/GraphEditorWindow.cs | 1280 +++++++++++++++++ .../Scripts/Windows/GraphEditorWindow.cs.meta | 11 + Editor/Scripts/Windows/TrackableWindow.cs | 378 +++++ .../Scripts/Windows/TrackableWindow.cs.meta | 14 + Editor/Scripts/Windows/WorldAnchorWindow.cs | 344 +++++ .../Scripts/Windows/WorldAnchorWindow.cs.meta | 11 + Editor/Scripts/Windows/WorldGraphWindow.cs | 304 ++++ .../Scripts/Windows/WorldGraphWindow.cs.meta | 14 + Editor/Scripts/Windows/WorldLinkWindow.cs | 515 +++++++ .../Scripts/Windows/WorldLinkWindow.cs.meta | 11 + Editor/Scripts/Windows/WorldStorageWindow.cs | 642 +++++++++ .../Windows/WorldStorageWindow.cs.meta | 14 + Editor/Scripts/WorldStoragePrefabs.cs | 36 + Editor/Scripts/WorldStoragePrefabs.cs.meta | 11 + Editor/Scripts/WorldStorageServerEditor.cs | 161 +-- .../Scripts/WorldStorageServerEditor.cs.meta | 2 +- Editor/Scripts/WorldStorageUserEditor.cs | 53 +- Editor/Scripts/WorldStorageUserEditor.cs.meta | 2 +- .../etsi.isg.arf.worldstorage.Editor.asmdef | 3 +- Runtime/Prefabs.meta | 8 + Runtime/Prefabs/ARFTrackable.prefab | 835 +++++++++++ Runtime/Prefabs/ARFTrackable.prefab.meta | 7 + Runtime/Prefabs/ARFWorldAnchor.prefab | 835 +++++++++++ Runtime/Prefabs/ARFWorldAnchor.prefab.meta | 7 + Runtime/Prefabs/ARFWorldLink.prefab | 555 +++++++ Runtime/Prefabs/ARFWorldLink.prefab.meta | 7 + Runtime/Resources.meta | 8 + Runtime/Resources/ARFPrefabs.asset | 17 + Runtime/Resources/ARFPrefabs.asset.meta | 8 + Runtime/Scripts/GraphEditor.meta | 8 + .../GraphEditor/AttachToWorldAnchor.cs | 29 + .../GraphEditor/AttachToWorldAnchor.cs.meta | 11 + Runtime/Scripts/GraphEditor/Data.cs | 16 + Runtime/Scripts/GraphEditor/Data.cs.meta | 11 + Runtime/Scripts/GraphEditor/LinkVisual.cs | 36 + .../Scripts/GraphEditor/LinkVisual.cs.meta | 11 + .../GraphEditor/WorldStorageCollections.cs | 26 + .../WorldStorageCollections.cs.meta | 11 + .../GraphEditor/WorldStorageRequest.cs | 167 +++ .../GraphEditor/WorldStorageRequest.cs.meta | 11 + 82 files changed, 8784 insertions(+), 159 deletions(-) create mode 100644 Editor/Images.meta create mode 100644 Editor/Images/anchor.png create mode 100644 Editor/Images/anchor.png.meta create mode 100644 Editor/Images/cloud.png create mode 100644 Editor/Images/cloud.png.meta create mode 100644 Editor/Images/link.png create mode 100644 Editor/Images/link.png.meta create mode 100644 Editor/Images/trackable.png create mode 100644 Editor/Images/trackable.png.meta create mode 100644 Editor/Images/warning.png create mode 100644 Editor/Images/warning.png.meta create mode 100644 Editor/Materials.meta create mode 100644 Editor/Materials/anchor.mat create mode 100644 Editor/Materials/anchor.mat.meta create mode 100644 Editor/Materials/blue.mat create mode 100644 Editor/Materials/blue.mat.meta create mode 100644 Editor/Materials/green.mat create mode 100644 Editor/Materials/green.mat.meta create mode 100644 Editor/Materials/link.mat create mode 100644 Editor/Materials/link.mat.meta create mode 100644 Editor/Materials/red.mat create mode 100644 Editor/Materials/red.mat.meta create mode 100644 Editor/Materials/trackable.mat create mode 100644 Editor/Materials/trackable.mat.meta create mode 100644 Editor/Scripts/Graph.meta create mode 100644 Editor/Scripts/Graph/ARFEdgeLink.cs create mode 100644 Editor/Scripts/Graph/ARFEdgeLink.cs.meta create mode 100644 Editor/Scripts/Graph/ARFGraphView.cs create mode 100644 Editor/Scripts/Graph/ARFGraphView.cs.meta create mode 100644 Editor/Scripts/Graph/ARFNode.cs create mode 100644 Editor/Scripts/Graph/ARFNode.cs.meta create mode 100644 Editor/Scripts/Graph/ARFNodeTrackable.cs create mode 100644 Editor/Scripts/Graph/ARFNodeTrackable.cs.meta create mode 100644 Editor/Scripts/Graph/ARFNodeWorldAnchor.cs create mode 100644 Editor/Scripts/Graph/ARFNodeWorldAnchor.cs.meta create mode 100644 Editor/Scripts/Graph/ARFPort.cs create mode 100644 Editor/Scripts/Graph/ARFPort.cs.meta create mode 100644 Editor/Scripts/Graph/WorldLinkListener.cs create mode 100644 Editor/Scripts/Graph/WorldLinkListener.cs.meta create mode 100644 Editor/Scripts/Windows.meta create mode 100644 Editor/Scripts/Windows/BaseWindow.cs create mode 100644 Editor/Scripts/Windows/BaseWindow.cs.meta create mode 100644 Editor/Scripts/Windows/GraphEditorWindow.cs create mode 100644 Editor/Scripts/Windows/GraphEditorWindow.cs.meta create mode 100644 Editor/Scripts/Windows/TrackableWindow.cs create mode 100644 Editor/Scripts/Windows/TrackableWindow.cs.meta create mode 100644 Editor/Scripts/Windows/WorldAnchorWindow.cs create mode 100644 Editor/Scripts/Windows/WorldAnchorWindow.cs.meta create mode 100644 Editor/Scripts/Windows/WorldGraphWindow.cs create mode 100644 Editor/Scripts/Windows/WorldGraphWindow.cs.meta create mode 100644 Editor/Scripts/Windows/WorldLinkWindow.cs create mode 100644 Editor/Scripts/Windows/WorldLinkWindow.cs.meta create mode 100644 Editor/Scripts/Windows/WorldStorageWindow.cs create mode 100644 Editor/Scripts/Windows/WorldStorageWindow.cs.meta create mode 100644 Editor/Scripts/WorldStoragePrefabs.cs create mode 100644 Editor/Scripts/WorldStoragePrefabs.cs.meta create mode 100644 Runtime/Prefabs.meta create mode 100644 Runtime/Prefabs/ARFTrackable.prefab create mode 100644 Runtime/Prefabs/ARFTrackable.prefab.meta create mode 100644 Runtime/Prefabs/ARFWorldAnchor.prefab create mode 100644 Runtime/Prefabs/ARFWorldAnchor.prefab.meta create mode 100644 Runtime/Prefabs/ARFWorldLink.prefab create mode 100644 Runtime/Prefabs/ARFWorldLink.prefab.meta create mode 100644 Runtime/Resources.meta create mode 100644 Runtime/Resources/ARFPrefabs.asset create mode 100644 Runtime/Resources/ARFPrefabs.asset.meta create mode 100644 Runtime/Scripts/GraphEditor.meta create mode 100644 Runtime/Scripts/GraphEditor/AttachToWorldAnchor.cs create mode 100644 Runtime/Scripts/GraphEditor/AttachToWorldAnchor.cs.meta create mode 100644 Runtime/Scripts/GraphEditor/Data.cs create mode 100644 Runtime/Scripts/GraphEditor/Data.cs.meta create mode 100644 Runtime/Scripts/GraphEditor/LinkVisual.cs create mode 100644 Runtime/Scripts/GraphEditor/LinkVisual.cs.meta create mode 100644 Runtime/Scripts/GraphEditor/WorldStorageCollections.cs create mode 100644 Runtime/Scripts/GraphEditor/WorldStorageCollections.cs.meta create mode 100644 Runtime/Scripts/GraphEditor/WorldStorageRequest.cs create mode 100644 Runtime/Scripts/GraphEditor/WorldStorageRequest.cs.meta diff --git a/Editor/Images.meta b/Editor/Images.meta new file mode 100644 index 0000000..e91faab --- /dev/null +++ b/Editor/Images.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +<<<<<<< HEAD +guid: 7d34ace7d2e2513479736d20d0c95ad0 +======= +guid: 959ac6161f5900d4aa7903c24bc5a31d +>>>>>>> develop +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Images/anchor.png b/Editor/Images/anchor.png new file mode 100644 index 0000000000000000000000000000000000000000..bb1804db730faff5a6f0a7523a8729085e8dae34 GIT binary patch literal 21219 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 literal 0 HcmV?d00001 diff --git a/Editor/Images/anchor.png.meta b/Editor/Images/anchor.png.meta new file mode 100644 index 0000000..b8da83a --- /dev/null +++ b/Editor/Images/anchor.png.meta @@ -0,0 +1,98 @@ +fileFormatVersion: 2 +guid: 000725cae67a4f7448f79fe2a478a50d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Images/cloud.png b/Editor/Images/cloud.png new file mode 100644 index 0000000000000000000000000000000000000000..a00dc22e5e0f7b506d089858b7ed281d3ed6092b GIT binary patch literal 31613 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 UvR{Iq%-&#bYHd<#bUy6=09?;xssI20 literal 0 HcmV?d00001 diff --git a/Editor/Images/cloud.png.meta b/Editor/Images/cloud.png.meta new file mode 100644 index 0000000..d55875b --- /dev/null +++ b/Editor/Images/cloud.png.meta @@ -0,0 +1,98 @@ +fileFormatVersion: 2 +guid: 8338d2b625f22b44095330be071b8e56 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Images/link.png b/Editor/Images/link.png new file mode 100644 index 0000000000000000000000000000000000000000..dda8f37b2a455617c9f692431928b0502e31747c GIT binary patch literal 18903 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 GzV$Cjsy(#; literal 0 HcmV?d00001 diff --git a/Editor/Images/link.png.meta b/Editor/Images/link.png.meta new file mode 100644 index 0000000..70c4fed --- /dev/null +++ b/Editor/Images/link.png.meta @@ -0,0 +1,98 @@ +fileFormatVersion: 2 +guid: fef18a27fe1e4a040b8cfda6b3b5c178 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Images/trackable.png b/Editor/Images/trackable.png new file mode 100644 index 0000000000000000000000000000000000000000..f31019b2f9ea607e3bfa127348fa17d80296938d GIT binary patch literal 14290 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 literal 0 HcmV?d00001 diff --git a/Editor/Images/trackable.png.meta b/Editor/Images/trackable.png.meta new file mode 100644 index 0000000..fb29933 --- /dev/null +++ b/Editor/Images/trackable.png.meta @@ -0,0 +1,98 @@ +fileFormatVersion: 2 +guid: 90d4635c9d0895c42bec0551c4e790ea +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Images/warning.png b/Editor/Images/warning.png new file mode 100644 index 0000000000000000000000000000000000000000..a989284db594278ae478f2e8cb1b8cafa036a229 GIT binary patch literal 55016 zcmeFZiC>Lr|2Te=2_s`L$W}}zNu>srkRlVOmC~Z9V~VClrBvFF2N|?*+O&rjZ93wV zv>nrkBQ080TBwwgXwhE3_xn1{^YQ!(zt?x>^(v?9zOL)N@AtWSSm)s4AJ_ayQPg7k zp#yppwE+IPfLb63zp|36<>1#mt9{!0DC$AbqREp#z~>DXhxD{5%3~8nF)vZnIQ)s( zO;IlJY!8E?cHN?=RgTe5j_iR2!9O$)9-wCM|M-IBV0eacRm+L#9GjGw z=?Loh;oMANQGb`0&q4s||NZy>DDeL%@c$zU6yI|-S(26$J>@74STP>2KrLsmYsWr5 zKYentCd9*uC6Q1Qtk+|qU)mlV9n!IMWGeHs?m#`g@RnZD4U_3jyj6OoT~)SkBP

Z9xEZhH_oV>RW?(%sY$ zt~ZiYf2*`BZYW~lebCl%3ADUZPjM%eez(zDJE4B3gvIsU`laQx-NDfc8?3%%iZ?`A zZsoi><@K&)oA+ScL^592Tg=~c+oSo1cBOBz>r*;c(_^DMB)ja2`pqgZXbXFKnAdbxI%^`&KAlDs(D*woOPA|u!GsZd`j ze9%Q0pJ%QxbZ8uV;V)wrViJ2(FD|CzZ0clio?fYFQjN;1rvXK#v6EM)SnwqGB{~p_ zl8P@cv!j13kV`Dw!1<)HE$OA&xH_vG}mc=^o3=n*UPuzB!YVC)=xe5VGdx-qun z2fEoU%PYT@W&ww2ynf5GpWI&NDo$}|@CbVcAM}Mb$u3STQQd*%bRB(5gCV`rVaZ_? ztFxc(o~n=a4Z%Z2BFUlW7Yx_+J@0H;T%mn;L_ekTV|lf$&2Ncj;b!gigKU8!gY3SE zNIcqcCZ7$zm=i}b3(iYR_;bN|r?hY$gHs4$qEJ*qJL zVSP~P-=n&l#u{j?nTJ}(?N~E6)ca?)mKFHQ&W9)Yl>U-__TZR8ueRuFmq?BGBFv zGTtOPY##QZMI{&xWF9#U&r-~r2AL|pTcUo--@(b3LL!&Odl+;1pq?ymMnk4wYI}^b6D-Q5 z=MTXz#^%~cmd-@3S^-E>0Nq zh$hva&kKMDD52W3MxbAm-|sQDadCRB;T`+scmA3_O{@`!OX*~nMl1>Lz6+bmq2)KJW)_CH&yZTE=h~){aPuR8dZlco!S*`GVQ%- zNx{QUkB2o0+3kdY`6hDQ#}c1o79O=-^D)~j zrbB=pXmn}sS4GL;RhqWbig;UmE4eMczecCGgEnKtT2vdaJC#Yxl;E~Nd43}7^H`bD+%k^r+ePM+OFqO6x;FI zM()??T>&k+A)qy(AV|zwzSbBRW#%#VJooBbFF73ZRcV)c#UD2AzI$g9MneC^-|#xY z-_W4%QS6NlMOJjCpx9@Nkuw6LYb6n @bgVdDf56-N&>%wPl&{ieX-^v`U*5%*C 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 1) + { + message += selection.Count + " elements ?"; + } + else + { + message += "this element ?"; + } + + //remove from the graph all the deleted elements + if (EditorUtility.DisplayDialog("Deleting elements", message, "Yes", "No")) + { + if (SaveInfo.instance.elemsToRemove == null) + { + SaveInfo.instance.elemsToRemove = new Dictionary(); + } + foreach (GraphElement elt in selection.ToArray()) + { + ARFNodeWorldAnchor nodeAnchor = elt as ARFNodeWorldAnchor; + if (nodeAnchor != null) + { + nodeAnchor.DisconnectAllPorts(this); + if (SaveInfo.instance.nodePositions.ContainsKey(nodeAnchor.GUID)) + { + SaveInfo.instance.elemsToRemove.Add(nodeAnchor.GUID, typeof(WorldAnchor)); + } + RemoveElement(elt); + continue; + } + ARFNodeTrackable nodeTrackable = elt as ARFNodeTrackable; + if (nodeTrackable != null) + { + nodeTrackable.DisconnectAllPorts(this); + if (SaveInfo.instance.nodePositions.ContainsKey(nodeTrackable.GUID)) + { + SaveInfo.instance.elemsToRemove.Add(nodeTrackable.GUID, typeof(Trackable)); + } + RemoveElement(elt); + continue; + } + ARFEdgeLink edgeLink = elt as ARFEdgeLink; + if (edgeLink != null) + { + edgeLink.input.Disconnect(edgeLink); + edgeLink.output.Disconnect(edgeLink); + if (SaveInfo.instance.linkIds.Contains(edgeLink.GUID)) + { + SaveInfo.instance.elemsToRemove.Add(edgeLink.GUID, typeof(WorldLink)); + } + RemoveElement(elt); + continue; + } + } + } + + GraphEditorWindow.ResetWindow(); + } + + public override void BuildContextualMenu(UnityEngine.UIElements.ContextualMenuPopulateEvent evt) + { + Vector2 localMousePos = evt.localMousePosition; + Vector2 actualGraphPosition = viewTransform.matrix.inverse.MultiplyPoint(localMousePos); + + if (!(evt.target is ARFNode || evt.target is Group || evt.target is ARFEdgeLink)) + { + evt.menu.AppendSeparator(); + evt.menu.AppendAction("Save graph", delegate + { + if (ServerAndLocalDifferent()) + { + SaveInServer(); + } + }, (DropdownMenuAction a) => DropdownMenuAction.Status.Normal); + evt.menu.AppendAction("Reload graph", delegate + { + if (ServerAndLocalDifferent() && EditorUtility.DisplayDialog("Saving node positions", "The World Graph has been modified. \nWould you like to push the modifications to the server ?", "Yes", "No")) + { + SaveInServer(); + } + Reload(); + SaveInfo.instance.toReFrame = true; + }, (DropdownMenuAction a) => DropdownMenuAction.Status.Normal); + evt.menu.AppendAction("Create Trackable", delegate + { + //generate the Trackables's attributes + EncodingInformationStructure trackableEncodingInformation = new EncodingInformationStructure() + { + DataFormat = EncodingInformationStructureDataFormat.OTHER, + Version = "0" + }; + + Transform3D localCRS = new Transform3D(); + for (int i = 0; i < 15; i++) + { + localCRS.Add(0); + } + localCRS.Add(1); + + Size trackableSize = new Size(); + for (int i = 0; i < 3; i++) + { + trackableSize.Add(0); + } + + string name = "DefaultTrackable"; + + //trying to add number after default name + var defaultNodes = nodes.ToList().Where(node => node.title.StartsWith("DefaultTrackable")); + if (defaultNodes.Any()) + { + for (int i = 0; i < defaultNodes.Count(); i++) + { + Debug.Log($"{i} : " + defaultNodes.ElementAt(i).title); + if (!(defaultNodes.Where(node => node.title.EndsWith((i + 1).ToString() + ")")).Any())) + { + name = name + " (" + (i + 1).ToString() + ")"; + break; + } + } + } + + Trackable trackable = new Trackable(name) + { + UUID = Guid.NewGuid(), + CreatorUUID = Guid.Parse(worldStorageUser.UUID), + TrackableType = TrackableType.OTHER, + TrackableEncodingInformation = trackableEncodingInformation, + TrackablePayload = new byte[64], + LocalCRS = localCRS, + Unit = UnitSystem.CM, + TrackableSize = trackableSize + }; + + selection.Clear(); + var node = CreateTrackableNode(trackable, actualGraphPosition.x, actualGraphPosition.y); + node.MarkUnsaved(); + GraphEditorWindow.ShowWindow((ARFNodeTrackable)node); + + }, (DropdownMenuAction a) => DropdownMenuAction.Status.Normal); + evt.menu.AppendAction("Create World Anchor", delegate + { + //generate the worldAnchor attributes + Transform3D localCRS = new Transform3D(); + for (int i = 0; i < 15; i++) + { + localCRS.Add(0); + } + localCRS.Add(1); + + Size worldAnchorSize = new Size(); + for (int i = 0; i < 3; i++) + { + worldAnchorSize.Add(0); + } + + string name = "DefaultWorldAnchor"; + + //trying to add number after default name + var defaultNodes = nodes.ToList().Where(node => node.title.StartsWith("DefaultWorldAnchor")); + if (defaultNodes.Any()) + { + for (int i = 0; i < defaultNodes.Count(); i++) + { + if (!(defaultNodes.Where(node => node.title.EndsWith((i + 1).ToString() + ")")).Any())) + { + name = name + " (" + (i + 1).ToString() + ")"; + break; + } + } + } + + WorldAnchor anchor = new WorldAnchor(name) + { + UUID = Guid.NewGuid(), + CreatorUUID = Guid.Parse(worldStorageUser.UUID), + LocalCRS = localCRS, + Unit = UnitSystem.CM, + WorldAnchorSize = worldAnchorSize + }; + + selection.Clear(); + var node = CreateAnchorNode(anchor, actualGraphPosition.x, actualGraphPosition.y); + node.MarkUnsaved(); + GraphEditorWindow.ShowWindow((ARFNodeWorldAnchor)node); + + }, (DropdownMenuAction a) => DropdownMenuAction.Status.Normal); + } + evt.menu.AppendSeparator(); + if (evt.target is ARFNode || evt.target is Group || evt.target is ARFEdgeLink) + { + evt.menu.AppendSeparator(); + evt.menu.AppendAction("Delete", delegate + { + DeleteSelectionCallback(AskUser.AskUser); + }, (DropdownMenuAction a) => canDeleteSelection ? DropdownMenuAction.Status.Normal : DropdownMenuAction.Status.Disabled); + evt.menu.AppendSeparator(); + } + } + + public bool ServerAndLocalDifferent() + { + if ((SaveInfo.instance.elemsToRemove.Count != 0) || (SaveInfo.instance.elemsToUpdate.Count != 0)) + { + return true; + } + foreach (ARFNode node in nodes) + { + float nodeX = node.GetPosition().x; + float nodeY = node.GetPosition().y; + if (!SaveInfo.instance.nodePositions.ContainsKey(node.GUID)) + { + return true; + } + else + { + float dataX = SaveInfo.instance.nodePositions[node.GUID].x; + float dataY = SaveInfo.instance.nodePositions[node.GUID].y; + if ((nodeX != dataX) || (nodeY != dataY)) + { + return true; + } + } + } + foreach (ARFEdgeLink edge in edges) + { + if (!SaveInfo.instance.linkIds.Contains(edge.GUID)) + { + return true; + } + } + return false; + } + + public override List GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter) + { + var cPorts = new List(); + ports.ForEach(funcCall: port => + { + if (startPort != port && startPort.node != port.node) cPorts.Add(port); + }); + return cPorts; + } + + public void PaintWorldStorage() + { + + List worldAnchors = WorldAnchorRequest.GetWorldAnchorsSync(worldStorageServer); + foreach (WorldAnchor worldAnchor in worldAnchors) + { + var waNode = new ARFNodeWorldAnchor(worldAnchor); + + Rect posTemp = new(26, 93, 160, 77); + SaveInfo.instance.nodePositions.TryGetValue(worldAnchor.UUID.ToString(), out posTemp); + waNode.SetPosition(posTemp); + + AddElement(waNode); + } + + List trackables = TrackableRequest.GetTrackablesSync(worldStorageServer); + foreach (Trackable trackable in trackables) + { + var tracknode = new ARFNodeTrackable(trackable); + + Rect posTemp = new(26, 93, 160, 77); + SaveInfo.instance.nodePositions.TryGetValue(trackable.UUID.ToString(), out posTemp); + tracknode.SetPosition(posTemp); + + AddElement(tracknode); + } + List worldLinks = WorldLinkRequest.GetWorldLinksSync(worldStorageServer); + foreach (WorldLink worldLink in worldLinks) + { + Debug.Log("ports"); + var portPair = GetPortsFromWorldLink(worldLink); + Debug.Log("edge " + (portPair.Key == null)+ " " + (portPair.Value == null)); + ARFEdgeLink edge = portPair.Key.ConnectTo(portPair.Value); + edge.worldLink = worldLink; + edge.GUID = worldLink.UUID.ToString(); + + AddElement(edge); + } + } + + internal ARFNodeTrackable CreateTrackableNode(Trackable track, float posX, float posY) + { + var tracknode = new ARFNodeTrackable(track); + Rect pos = new Rect(RoundToNearestHalf(posX), RoundToNearestHalf(posY), 160, 77); + tracknode.SetPosition(pos); + + AddElement(tracknode); + return tracknode; + } + + internal ARFNodeWorldAnchor CreateAnchorNode(WorldAnchor wa, float posX, float posY) + { + var waNode = new ARFNodeWorldAnchor(wa); + + Rect pos = new Rect(RoundToNearestHalf(posX), RoundToNearestHalf(posY), 160, 77); + waNode.SetPosition(pos); + + AddElement(waNode); + return waNode; + } + + internal ARFEdgeLink CreateLink(WorldLink worldLink) + { + var portPair = GetPortsFromWorldLink(worldLink); + ARFEdgeLink edge = portPair.Key.ConnectTo(portPair.Value); + edge.worldLink = worldLink; + Debug.Log(worldLink.UUID.ToString()); + edge.GUID = worldLink.UUID.ToString(); + + AddElement(edge); + return edge; + } + + public void Reload() + { + GraphEditorWindow.ResetWindow(); + DeleteElements(graphElements); + SaveInfo.instance.InitNodePos(worldStorageServer, worldStorageUser); + PaintWorldStorage(); + FrameAllElements(); + } + + public Dictionary GetNodePositions() + { + Dictionary ret = new Dictionary(); + foreach (ARFNode elem in nodes) + { + ret.Add(elem.GUID, elem.GetPosition()); + } + return ret; + } + + private KeyValuePair GetPortsFromWorldLink(WorldLink worldLink) + { + var ret = new KeyValuePair(); + + //To + Guid idTo = worldLink.UUIDTo; + Port portIn = null; + switch (worldLink.TypeTo) + { + case TypeWorldStorage.TRACKABLE: + foreach (GraphElement node in this.graphElements) + { + ARFNodeTrackable nodeTrackable = node as ARFNodeTrackable; + if ((nodeTrackable != null) && (nodeTrackable.trackable.UUID == idTo)) + { + portIn = nodeTrackable.portIn; + break; + } + } + break; + case TypeWorldStorage.ANCHOR: + foreach (GraphElement node in this.graphElements) + { + ARFNodeWorldAnchor nodeAnchor = node as ARFNodeWorldAnchor; + if ((nodeAnchor != null) && nodeAnchor.worldAnchor.UUID == idTo) + { + portIn = nodeAnchor.portIn; + break; + } + } + break; + default: + Debug.Log("what are you doing here..."); + break; + } + + //From + Guid idFrom = worldLink.UUIDFrom; + Port portOut = null; + switch (worldLink.TypeFrom) + { + case TypeWorldStorage.TRACKABLE: + foreach (GraphElement node in this.graphElements) + { + ARFNodeTrackable nodeTrackable = node as ARFNodeTrackable; + if ((nodeTrackable != null) && (nodeTrackable.trackable.UUID == idFrom)) + { + portOut = nodeTrackable.portOut; + break; + } + } + break; + case TypeWorldStorage.ANCHOR: + foreach (GraphElement node in this.graphElements) + { + ARFNodeWorldAnchor nodeAnchor = node as ARFNodeWorldAnchor; + if ((nodeAnchor != null) && nodeAnchor.worldAnchor.UUID == idFrom) + { + portOut = nodeAnchor.portOut; + break; + } + } + break; + default: + Debug.Log("what are you doing here..."); + break; + } + + if ((portOut != null) && (portIn != null)) + { + ret = new KeyValuePair(portOut, portIn); + } + + return ret; + } + + // + // R�sum�: + // Calculate the rectangle size and position to fit all elements in graph. + // + // Param�tres�: + // container: + // This should be the view container. + // + // Retourne�: + // The calculated rectangle. + public override Rect CalculateRectToFitAll(VisualElement container) + { + Rect rectToFit = container.layout; + bool reachedFirstChild = false; + graphElements.ForEach(delegate (GraphElement ge) + { + if (!(ge is ARFEdgeLink) && !(ge is Port)) + { + if (!reachedFirstChild) + { + rectToFit = ge.ChangeCoordinatesTo(contentViewContainer, ge.contentRect); + reachedFirstChild = true; + } + else + { + rectToFit = RectUtils.Encompass(rectToFit, ge.ChangeCoordinatesTo(contentViewContainer, ge.contentRect)); + } + } + }); + return rectToFit; + } + + //k_FrameBorder is private readOnly graphView attribute, had to redeclare it to access it + private readonly int k_FrameBorder = 30; + public void FrameAllElements() + { + Vector3 frameTranslation = Vector3.zero; + Vector3 frameScaling = Vector3.one; + var rectToFit = CalculateRectToFitAll(contentViewContainer); + CalculateFrameTransform(rectToFit, layout, k_FrameBorder, out frameTranslation, out frameScaling); + Matrix4x4.TRS(frameTranslation, Quaternion.identity, frameScaling); + UpdateViewTransform(frameTranslation, frameScaling); + } + + //method to predict the position of a node (the float that will be saved in the PositionInfo singleton) + public static float RoundToNearestHalf(float a) + { + return a = Mathf.Round(a * 2f) * 0.5f; + } + + //Save all modified/deleted/added elements to the server + public void SaveInServer() + { + //DELETE ELEMENTS FROM THE SERVER + foreach (KeyValuePair elemToRemove in SaveInfo.instance.elemsToRemove) + { + string typeName = elemToRemove.Value.Name; + switch (typeName) + { + case nameof(Trackable): + TrackableRequest.DeleteTrackableAsync(worldStorageServer, Guid.Parse(elemToRemove.Key), (response) => { }); + break; + case nameof(WorldAnchor): + Debug.Log("delete worldanchor"); + WorldAnchorRequest.DeleteWorldAnchorAsync(worldStorageServer, Guid.Parse(elemToRemove.Key), (response) => { }); + break; + case nameof(WorldLink): + WorldLinkRequest.DeleteWorldLinkAsync(worldStorageServer, Guid.Parse(elemToRemove.Key), (response) => { }); + break; + default: + Debug.Log("oops"); + break; + } + } + + // UPDATE AND ADD ELEMENTS + foreach (ARFNode node in nodes) + { + if (!SaveInfo.instance.nodePositions.ContainsKey(node.GUID)) + { + // POST TRACKABLE + if (node is ARFNodeTrackable aRFNodeTrackable) + { + var posX = new Collection(); + posX.Add(aRFNodeTrackable.GetPosition().x.ToString()); + var posY = new Collection(); + posY.Add(aRFNodeTrackable.GetPosition().y.ToString()); + Trackable trackable = aRFNodeTrackable.trackable; + trackable.KeyvalueTags["unityAuthoringPosX"] = posX; + trackable.KeyvalueTags["unityAuthoringPosY"] = posY; + TrackableRequest.CreateTrackableAsync(worldStorageServer, trackable, (response) => + { + //change the uuid in its edges, if there is a new edge to be added in the world storage it needs to have the correct uuid + String uuid = response.result; + + uuid = uuid.Replace("\"", ""); + foreach (ARFEdgeLink edge in aRFNodeTrackable.portIn.connections) + { + edge.worldLink.UUIDTo = Guid.Parse(uuid); + } + foreach (ARFEdgeLink edge in aRFNodeTrackable.portOut.connections) + { + edge.worldLink.UUIDFrom = Guid.Parse(uuid); + } + aRFNodeTrackable.trackable.UUID = Guid.Parse(uuid); + aRFNodeTrackable.GUID = uuid; + aRFNodeTrackable.title = trackable.Name; + }); + } + + // POST WORLDANCHOR + if (node is ARFNodeWorldAnchor aRFNodeWorldAnchor) + { + var posX = new Collection(); + posX.Add(aRFNodeWorldAnchor.GetPosition().x.ToString()); + var posY = new Collection(); + posY.Add(aRFNodeWorldAnchor.GetPosition().y.ToString()); + WorldAnchor worldAnchor = aRFNodeWorldAnchor.worldAnchor; + worldAnchor.KeyvalueTags["unityAuthoringPosX"] = posX; + worldAnchor.KeyvalueTags["unityAuthoringPosY"] = posY; + + WorldAnchorRequest.CreateWorldAnchorAsync(worldStorageServer, worldAnchor, (response) => + { + + String uuid = response.result; + //change the uuid in its edges, if there is a new edge to be added in the world storage it needs to have the correct uuid + uuid = uuid.Replace("\"", ""); + foreach (ARFEdgeLink edge in aRFNodeWorldAnchor.portIn.connections) + { + edge.worldLink.UUIDTo = Guid.Parse(uuid); + } + foreach (ARFEdgeLink edge in aRFNodeWorldAnchor.portOut.connections) + { + edge.worldLink.UUIDFrom = Guid.Parse(uuid); + } + aRFNodeWorldAnchor.worldAnchor.UUID = Guid.Parse(uuid); + aRFNodeWorldAnchor.GUID = uuid; + aRFNodeWorldAnchor.title = worldAnchor.Name; + }); + } + } + else + { + float xLocal = node.GetPosition().x; + float yLocal = node.GetPosition().y; + float xServer = SaveInfo.instance.nodePositions[node.GUID].x; ; + float yServer = SaveInfo.instance.nodePositions[node.GUID].y; + if (((xLocal != xServer) || (yLocal != yServer)) || SaveInfo.instance.elemsToUpdate.Contains(node.GUID)) + { + if (node is ARFNodeTrackable aRFNodeTrackable) + { + var posX = new Collection(); + posX.Add(aRFNodeTrackable.GetPosition().x.ToString()); + var posY = new Collection(); + posY.Add(aRFNodeTrackable.GetPosition().y.ToString()); + Trackable trackable = aRFNodeTrackable.trackable; + trackable.KeyvalueTags["unityAuthoringPosX"] = posX; + trackable.KeyvalueTags["unityAuthoringPosY"] = posY; + TrackableRequest.UpdateTrackableAsync(worldStorageServer, trackable, (response) => + { + aRFNodeTrackable.title = trackable.Name; + }); + } + if (node is ARFNodeWorldAnchor aRFNodeWorldAnchor) + { + var posX = new Collection(); + posX.Add(aRFNodeWorldAnchor.GetPosition().x.ToString()); + var posY = new Collection(); + posY.Add(aRFNodeWorldAnchor.GetPosition().y.ToString()); + WorldAnchor worldAnchor = aRFNodeWorldAnchor.worldAnchor; + worldAnchor.KeyvalueTags["unityAuthoringPosX"] = posX; + worldAnchor.KeyvalueTags["unityAuthoringPosY"] = posY; + WorldAnchorRequest.UpdateWorldAnchorAsync(worldStorageServer, worldAnchor, (response) => + { + aRFNodeWorldAnchor.title = worldAnchor.Name; + }); + } + } + } + node.MarkSaved(); + } + foreach (ARFEdgeLink edge in edges) + { + if (edge is ARFEdgeLink aRFEdgeLink) + { + if (!SaveInfo.instance.linkIds.Contains(aRFEdgeLink.GUID)) + { + WorldLink worldLink = aRFEdgeLink.worldLink; + WorldLinkRequest.CreateWorldLinkAsync(worldStorageServer, worldLink, (response) => + { + string uuid = response.result; + uuid = uuid.Replace("\"", ""); + + aRFEdgeLink.worldLink.UUID = Guid.Parse(uuid); + aRFEdgeLink.GUID = uuid; + }); + } + else if (SaveInfo.instance.elemsToUpdate.Contains(aRFEdgeLink.GUID)) + { + WorldLink worldLink = aRFEdgeLink.worldLink; + WorldLinkRequest.UpdateWorldLinkAsync(worldStorageServer, worldLink, (response) => { }); + } + aRFEdgeLink.MarkSaved(); + } + } + SaveInfo.instance.InitNodePos(worldStorageServer, worldStorageUser); + + GraphEditorWindow.ResetWindow(); + } + } +} \ No newline at end of file diff --git a/Editor/Scripts/Graph/ARFGraphView.cs.meta b/Editor/Scripts/Graph/ARFGraphView.cs.meta new file mode 100644 index 0000000..e0b1d23 --- /dev/null +++ b/Editor/Scripts/Graph/ARFGraphView.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 000c7511b9bdea24cb6c962ca1ae26ca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/Graph/ARFNode.cs b/Editor/Scripts/Graph/ARFNode.cs new file mode 100644 index 0000000..dbda198 --- /dev/null +++ b/Editor/Scripts/Graph/ARFNode.cs @@ -0,0 +1,140 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2024 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: July 2022 +// + +#define USING_OPENAPI_GENERATOR // alt. is Swagger + +using System; + +using UnityEditor; +using UnityEngine.UIElements; +using UnityEditor.Experimental.GraphView; +using UnityEngine; + +using ETSI.ARF.WorldStorage.Editor.Graph; +using ETSI.ARF.OpenAPI.WorldStorage; + +namespace ETSI.ARF.WorldStorage.UI +{ + public abstract class ARFNode : Node + { + public string GUID; + public bool entryPoint = false; + public ARFPort portOut; + public ARFPort portIn; + public GUID id; + + public Image savedIcon; + + public ARFNode() + { + } + public override Port InstantiatePort(Orientation orientation, Direction direction, Port.Capacity capacity, Type type) + { + switch (direction) + { + case Direction.Input: + portIn = ARFPort.CreateARF(orientation, direction, capacity, type); + return portIn; + case Direction.Output: + portOut = ARFPort.CreateARF(orientation, direction, capacity, type); + return portOut; + default: + return null; + } + } + + public void DisconnectAllPorts(ARFGraphView graphView) + { + DisconnectInputPorts(graphView); + DisconnectOutputPorts(graphView); + } + + private void DisconnectInputPorts(ARFGraphView graphView) + { + DisconnectPorts(inputContainer, graphView); + } + + private void DisconnectOutputPorts(ARFGraphView graphView) + { + DisconnectPorts(outputContainer, graphView); + } + + private void DisconnectPorts(VisualElement container, ARFGraphView graphView) + { + foreach (Port port in container.Children()) + { + if (!port.connected) + { + continue; + } + + graphView.DeleteElements(port.connections); + } + } + + public Port GeneratePort(ARFNode node, Direction portDirection, Port.Capacity capacity = Port.Capacity.Multi) + { + return node.InstantiatePort(Orientation.Horizontal, portDirection, capacity, typeof(int)); // dummy + } + + //override the BuildContextualMenu method to prevent the "disconnect" option from appearing in the contextual menu + public override void BuildContextualMenu(ContextualMenuPopulateEvent evt) + { + } + + public abstract TypeWorldStorage GetElemType(); + public void MarkUnsaved() + { + if(savedIcon == null) + { + //the icon to add if the node does not correspond to an element in the server + Texture2D warningImage = (Texture2D)AssetDatabase.LoadAssetAtPath("Packages/etsi.isg.arf.worldstorage/Editor/Images/cloud.png", typeof(Texture2D)); + savedIcon = new Image + { + image = warningImage, + scaleMode = ScaleMode.ScaleToFit + }; + savedIcon.style.width = 25; + savedIcon.style.height = 25; + savedIcon.style.minWidth = 25; + savedIcon.style.minHeight = 25; + savedIcon.style.left = 8; + savedIcon.style.paddingRight = 8; + savedIcon.style.alignSelf = Align.Center; + + } + if (!titleContainer.Contains(savedIcon)) + { + titleContainer.Insert(0,savedIcon); + } + tooltip = "This element is not synchronized with the World Storage"; + } + + public void MarkSaved() + { + if (titleContainer.Contains(savedIcon)) + { + titleContainer.Remove(savedIcon); + tooltip = ""; + } + } + + } +} \ No newline at end of file diff --git a/Editor/Scripts/Graph/ARFNode.cs.meta b/Editor/Scripts/Graph/ARFNode.cs.meta new file mode 100644 index 0000000..97a115b --- /dev/null +++ b/Editor/Scripts/Graph/ARFNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0216cf1af3743f2429eb4b01db300b0e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/Graph/ARFNodeTrackable.cs b/Editor/Scripts/Graph/ARFNodeTrackable.cs new file mode 100644 index 0000000..08284e7 --- /dev/null +++ b/Editor/Scripts/Graph/ARFNodeTrackable.cs @@ -0,0 +1,85 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2024 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: June 2024 +// + +#define USING_OPENAPI_GENERATOR // alt. is Swagger + +using UnityEngine; +using UnityEngine.UIElements; +using UnityEditor; +using UnityEditor.Experimental.GraphView; + +using ETSI.ARF.WorldStorage.Editor.Windows; +using ETSI.ARF.OpenAPI.WorldStorage; + +namespace ETSI.ARF.WorldStorage.UI +{ + public class ARFNodeTrackable : ARFNode + { + public Trackable trackable; + + public ARFNodeTrackable(Trackable trackable) + { + this.trackable = trackable; + this.GUID = trackable.UUID.ToString(); + this.title = trackable.Name; + + /*COLOR*/ + var colorRectangle = new VisualElement(); + colorRectangle.style.height = 160; + colorRectangle.style.height = 5; + colorRectangle.style.backgroundColor = new Color(1, 0.31f, 0.31f, 0.9f); + //get the index of the title container + int titleIndex = mainContainer.hierarchy.IndexOf(titleContainer); + mainContainer.Insert(titleIndex+1, colorRectangle); + + /*PORTS*/ + var portIn = GeneratePort(this, Direction.Input, Port.Capacity.Multi); + portIn.portColor = new Color(0.66f, 0.39f, 1, 0.77f); + portIn.portName = "Target"; // "Input" + //portIn.AddManipulator(new EdgeConnector(new WorldLinkListener())); + inputContainer.Add(portIn); + + var portOut = GeneratePort(this, Direction.Output, Port.Capacity.Multi); + portOut.portColor = new Color(0.66f, 0.39f, 1, 0.77f); + portOut.portName = "Source"; // "Output"; + //portOut.AddManipulator(new EdgeConnector(new WorldLinkListener())); ; + outputContainer.Add(portOut); + + RefreshExpandedState(); + RefreshPorts(); + + /*MANIPULATOR*/ + var doubleClickManipulator = new Clickable(Clicked); + doubleClickManipulator.activators.Clear(); + doubleClickManipulator.activators.Add(new ManipulatorActivationFilter { button = MouseButton.LeftMouse, clickCount = 2 }); + this.AddManipulator(doubleClickManipulator); + } + + public void Clicked() + { + Debug.Log(trackable.ToJson()); + GraphEditorWindow.ShowWindow(this); + } + public override TypeWorldStorage GetElemType() + { + return TypeWorldStorage.TRACKABLE; + } + } +} \ No newline at end of file diff --git a/Editor/Scripts/Graph/ARFNodeTrackable.cs.meta b/Editor/Scripts/Graph/ARFNodeTrackable.cs.meta new file mode 100644 index 0000000..17e98f2 --- /dev/null +++ b/Editor/Scripts/Graph/ARFNodeTrackable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 01bfb1a0a4a788c48a6c6675034ba8d5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/Graph/ARFNodeWorldAnchor.cs b/Editor/Scripts/Graph/ARFNodeWorldAnchor.cs new file mode 100644 index 0000000..2a3c003 --- /dev/null +++ b/Editor/Scripts/Graph/ARFNodeWorldAnchor.cs @@ -0,0 +1,79 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2024 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: June 2024 +// + +using UnityEngine; +using UnityEngine.UIElements; +using UnityEditor.Experimental.GraphView; + +using ETSI.ARF.WorldStorage.Editor.Windows; +using ETSI.ARF.OpenAPI.WorldStorage; + +namespace ETSI.ARF.WorldStorage.UI +{ + public class ARFNodeWorldAnchor : ARFNode + { + public WorldAnchor worldAnchor; + + public ARFNodeWorldAnchor(WorldAnchor worldAnchor) + { + this.worldAnchor = worldAnchor; + this.GUID = worldAnchor.UUID.ToString(); + this.title = worldAnchor.Name; + + /*COLOR*/ + var colorRectangle = new VisualElement(); + colorRectangle.style.height = 160; + colorRectangle.style.height = 5; + colorRectangle.style.backgroundColor = new Color(1, 0.7f, 0, 0.9f); + mainContainer.Insert(1, colorRectangle); + + /*PORTS*/ + var portIn = GeneratePort(this, Direction.Input, Port.Capacity.Multi); + portIn.portColor = new Color(0.66f, 0.39f, 1, 0.77f); + portIn.portName = "Target"; // "Input"; + //portIn.AddManipulator(new EdgeConnector(new WorldLinkListener())); + inputContainer.Add(portIn); + + var portOut = GeneratePort(this, Direction.Output, Port.Capacity.Multi); + portOut.portColor = new Color(0.66f, 0.39f, 1, 0.77f); + portOut.portName = "Source"; // "Output"; + //portOut.AddManipulator(new EdgeConnector(new WorldLinkListener())); + outputContainer.Add(portOut); + + RefreshExpandedState(); + RefreshPorts(); + + /*MANIPULATOR*/ + var doubleClickManipulator = new Clickable(Clicked); + doubleClickManipulator.activators.Clear(); + doubleClickManipulator.activators.Add(new ManipulatorActivationFilter { button = MouseButton.LeftMouse, clickCount = 2 }); + this.AddManipulator(doubleClickManipulator); + } + + public void Clicked() + { + GraphEditorWindow.ShowWindow(this); + } + public override TypeWorldStorage GetElemType() + { + return TypeWorldStorage.ANCHOR; + } + } +} \ No newline at end of file diff --git a/Editor/Scripts/Graph/ARFNodeWorldAnchor.cs.meta b/Editor/Scripts/Graph/ARFNodeWorldAnchor.cs.meta new file mode 100644 index 0000000..bb1bb7e --- /dev/null +++ b/Editor/Scripts/Graph/ARFNodeWorldAnchor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 21e22c1ed011b7a4da95fad83be1d9fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/Graph/ARFPort.cs b/Editor/Scripts/Graph/ARFPort.cs new file mode 100644 index 0000000..9728bd1 --- /dev/null +++ b/Editor/Scripts/Graph/ARFPort.cs @@ -0,0 +1,80 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2024 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: June 2024 +// + +using System; +using System.Collections.Generic; +using UnityEditor.Experimental.GraphView; +using UnityEngine; +using UnityEngine.UIElements; + +using ETSI.ARF.WorldStorage.Editor.Windows; +using ETSI.ARF.WorldStorage.UI; +using ETSI.ARF.OpenAPI.WorldStorage; + +namespace ETSI.ARF.WorldStorage.Editor.Graph +{ + public class ARFPort : Port + { + protected ARFPort(Orientation portOrientation, Direction portDirection, Capacity portCapacity, Type type) : base(portOrientation, portDirection, portCapacity, type) + { + } + + public override void Connect(Edge edge) + { + base.Connect(edge); + ARFNode fromNode = edge.output.node as ARFNode; + ARFNode toNode = edge.input.node as ARFNode; + + if (edge is ARFEdgeLink aRFedge) + { + Transform3D transform = new Transform3D(); + for (int i = 0; i < 15; i++) + { + transform.Add(0); + } + transform.Add(1); + + WorldLink worldLink = new WorldLink() + { + UUID = Guid.NewGuid(), + CreatorUUID = Guid.Parse(SaveInfo.instance.worldStorageUser.UUID), + UUIDFrom = Guid.Parse(fromNode.GUID), + UUIDTo = Guid.Parse(toNode.GUID), + TypeFrom = fromNode.GetElemType(), + TypeTo = toNode.GetElemType(), + Transform = transform, + Unit = UnitSystem.CM + }; + aRFedge.worldLink = worldLink; + } + } + + public static ARFPort CreateARF(Orientation orientation, Direction direction, Capacity capacity, Type type) where TEdge : Edge, new() + { + WorldLinkListener listener = new WorldLinkListener(); + ARFPort port = new(orientation, direction, capacity, type) + { + m_EdgeConnector = new EdgeConnector(listener) + }; + port.AddManipulator(port.m_EdgeConnector); + return port; + } + } +} \ No newline at end of file diff --git a/Editor/Scripts/Graph/ARFPort.cs.meta b/Editor/Scripts/Graph/ARFPort.cs.meta new file mode 100644 index 0000000..6d043fd --- /dev/null +++ b/Editor/Scripts/Graph/ARFPort.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c67fa4402011954bb65be6215d52512 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/Graph/WorldLinkListener.cs b/Editor/Scripts/Graph/WorldLinkListener.cs new file mode 100644 index 0000000..3133404 --- /dev/null +++ b/Editor/Scripts/Graph/WorldLinkListener.cs @@ -0,0 +1,98 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2024 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: June 2024 +// + +using UnityEngine; +using ETSI.ARF.WorldStorage.Editor.Windows; +using System.Collections.Generic; +using UnityEditor.Experimental.GraphView; +using static UnityEditor.Experimental.GraphView.Port; + +namespace ETSI.ARF.WorldStorage.Editor.Graph +{ + public class WorldLinkListener : IEdgeConnectorListener + { + private GraphViewChange m_GraphViewChange; + + private List m_EdgesToCreate; + + private List m_EdgesToDelete; + + public WorldLinkListener() + { + m_EdgesToCreate = new List(); + m_EdgesToDelete = new List(); + m_GraphViewChange.edgesToCreate = m_EdgesToCreate; + } + public void OnDrop(GraphView graphView, Edge edge) + { + m_EdgesToCreate.Clear(); + m_EdgesToCreate.Add(edge); + m_EdgesToDelete.Clear(); + if (edge.input.capacity == Capacity.Single) + { + foreach (Edge connection in edge.input.connections) + { + if (connection != edge) + { + m_EdgesToDelete.Add(connection); + } + } + } + + if (edge.output.capacity == Capacity.Single) + { + foreach (Edge connection2 in edge.output.connections) + { + if (connection2 != edge) + { + m_EdgesToDelete.Add(connection2); + } + } + } + + if (m_EdgesToDelete.Count > 0) + { + graphView.DeleteElements(m_EdgesToDelete); + } + + List edgesToCreate = m_EdgesToCreate; + if (graphView.graphViewChanged != null) + { + edgesToCreate = graphView.graphViewChanged(m_GraphViewChange).edgesToCreate; + } + + foreach (Edge item in edgesToCreate) + { + graphView.AddElement(item); + edge.input.Connect(item); + edge.output.Connect(item); + } + if (!SaveInfo.instance.linkIds.Contains(((ARFEdgeLink)edge).GUID)) + { + ((ARFEdgeLink)edge).MarkUnsaved(); + } + GraphEditorWindow.ShowWindow((ARFEdgeLink)edge); + } + + public void OnDropOutsidePort(Edge edge, Vector2 position) + { + } + } +} \ No newline at end of file diff --git a/Editor/Scripts/Graph/WorldLinkListener.cs.meta b/Editor/Scripts/Graph/WorldLinkListener.cs.meta new file mode 100644 index 0000000..e19f2ea --- /dev/null +++ b/Editor/Scripts/Graph/WorldLinkListener.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 54dbfcfdc75de1b46bc7da09df52db34 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/Windows.meta b/Editor/Scripts/Windows.meta new file mode 100644 index 0000000..bf1141a --- /dev/null +++ b/Editor/Scripts/Windows.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fbbff3217b2a8cd428764d83150c7b22 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/Windows/BaseWindow.cs b/Editor/Scripts/Windows/BaseWindow.cs new file mode 100644 index 0000000..64bba1e --- /dev/null +++ b/Editor/Scripts/Windows/BaseWindow.cs @@ -0,0 +1,118 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2024 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: June 2024 +// + +#define isDEBUG + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +using UnityEngine; +using UnityEditor; +using TMPro; + +using ETSI.ARF.WorldStorage.REST; +using ETSI.ARF.OpenAPI.WorldStorage; + +namespace ETSI.ARF.WorldStorage.UI +{ + public abstract class BaseWindow : EditorWindow + { + [HideInInspector] public WorldStorageServer worldStorageServer; + [HideInInspector] public WorldStorageUser worldStorageUser; + + [SerializeField] public List trackables = new List(); + + // + // Keyvalues + // + [SerializeField] protected KeyvalueTagList keyValueTags = new KeyvalueTagList(); + protected List<(string, string)> keyValuesFixed = new List<(string, string)>(3) + { + ("", ""),("", ""),("", "") + }; + protected void OutputKeyValue(int n) + { + string i1 = keyValuesFixed[n].Item1; + string i2 = keyValuesFixed[n].Item2; + i1 = EditorGUILayout.TextField("Key " + n, i1); + i2 = EditorGUILayout.TextField("Value " + n, i2); + keyValuesFixed[n] = (i1, i2); + } + + // + // UI stuffs + // + protected bool groupEnabled; + protected bool repaint = false; + protected Vector2 scrollPos; + protected Color ori; + protected GUIStyle gsTest; + protected string saveText = "Save"; + + public void Update() + { + if (repaint) + { + Repaint(); + repaint = false; + } + } + + void OnGUI() + { + ori = GUI.backgroundColor; // remember ori color + + gsTest = new GUIStyle("window"); + //gsTest.normal.textColor = WorldStorageWindow.arfColors[0]; + gsTest.fontStyle = FontStyle.Bold; + gsTest.alignment = TextAnchor.UpperLeft; + gsTest.fontSize = 16; + + scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.ExpandWidth(true)); + WorldStorageWindow.DrawCopyright(); + + DrawUIStuffs(); + + EditorGUILayout.EndScrollView(); + + if (GUILayout.Button("Close Window")) + { + Close(); + } + } + + public abstract void DrawUIStuffs(); + + public virtual void GetParams() + { + } + + public virtual void AddObject() + { + } + + public virtual T GenerateObject() + { + return default(T); + } + } +} \ No newline at end of file diff --git a/Editor/Scripts/Windows/BaseWindow.cs.meta b/Editor/Scripts/Windows/BaseWindow.cs.meta new file mode 100644 index 0000000..eed84fa --- /dev/null +++ b/Editor/Scripts/Windows/BaseWindow.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: b879c85f4eccbee40a78e1a01aaf77ca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - m_ViewDataDictionary: {instanceID: 0} + - worldStorageServer: {fileID: 11400000, guid: 4f997253243de534dad12937f1284975, type: 2} + - worldStorageUser: {instanceID: 0} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/Windows/GraphEditorWindow.cs b/Editor/Scripts/Windows/GraphEditorWindow.cs new file mode 100644 index 0000000..d1d7aaf --- /dev/null +++ b/Editor/Scripts/Windows/GraphEditorWindow.cs @@ -0,0 +1,1280 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2024 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: June 2024 +// + +using System; +using System.Collections.Generic; + +using UnityEditor; +using UnityEngine; + +using ETSI.ARF.WorldStorage.REST; +using ETSI.ARF.WorldStorage.UI; +using ETSI.ARF.WorldStorage.Editor.Graph; +using ETSI.ARF.OpenAPI.WorldStorage; +using System.Collections.ObjectModel; + +namespace ETSI.ARF.WorldStorage.Editor.Windows +{ + public class GraphEditorWindow : EditorWindow + { + public enum GraphEditorType + { + TRACKABLE, + WORLDANCHOR, + WORLDLINK, + NULL + } + + public GraphEditorType type; + + public ARFNodeTrackable trackableNode; + public ARFNodeWorldAnchor worldAnchorNode; + public ARFEdgeLink worldLinkEdge; + + public Trackable trackable; + public WorldAnchor worldAnchor; + public WorldLink worldLink; + + public Vector3 local_size; + public Vector3 local_rot; + public Vector3 local_pos; + + //test + string m_newKey = ""; + List m_newValues = new List(); + + // UI stuffs + private Vector2 scrollPos; + static public GraphEditorWindow winSingleton; + + public void OnEnable() + { + ResetWindow(); + } + + public static void ResetWindow() + { + Type inspectorType = Type.GetType("UnityEditor.InspectorWindow,UnityEditor.dll"); + winSingleton = GetWindow("Element Editor", true, inspectorType); + winSingleton.trackable = null; + winSingleton.worldAnchor = null; + winSingleton.worldLink = null; + + winSingleton.trackableNode = null; + winSingleton.worldAnchorNode = null; + winSingleton.worldLinkEdge = null; + + winSingleton.local_size = Vector3.zero; + winSingleton.local_rot = Vector3.zero; + winSingleton.local_pos = Vector3.zero; + + winSingleton.type = GraphEditorType.NULL; + } + + public static void ShowWindow(ARFNodeTrackable trackableNode) + { + Type inspectorType = Type.GetType("UnityEditor.InspectorWindow,UnityEditor.dll"); + winSingleton = GetWindow("Element Editor", true, inspectorType); + winSingleton.type = GraphEditorType.TRACKABLE; + + winSingleton.trackable = null; + winSingleton.worldAnchor = null; + winSingleton.worldLink = null; + + winSingleton.trackableNode = null; + winSingleton.worldAnchorNode = null; + winSingleton.worldLinkEdge = null; + + winSingleton.trackableNode = trackableNode; + winSingleton.trackable = trackableNode.trackable; + + winSingleton.local_size = new Vector3((float)winSingleton.trackable.TrackableSize[0], (float)winSingleton.trackable.TrackableSize[1], (float)winSingleton.trackable.TrackableSize[2]); + if (winSingleton.trackable.LocalCRS.Count == 16) + { + Matrix4x4 localCRS = new Matrix4x4(); + localCRS.m00 = winSingleton.trackable.LocalCRS[0]; localCRS.m01 = winSingleton.trackable.LocalCRS[1]; localCRS.m02 = winSingleton.trackable.LocalCRS[2]; localCRS.m03 = winSingleton.trackable.LocalCRS[3]; + localCRS.m10 = winSingleton.trackable.LocalCRS[4]; localCRS.m11 = winSingleton.trackable.LocalCRS[5]; localCRS.m12 = winSingleton.trackable.LocalCRS[6]; localCRS.m13 = winSingleton.trackable.LocalCRS[7]; + localCRS.m20 = winSingleton.trackable.LocalCRS[8]; localCRS.m21 = winSingleton.trackable.LocalCRS[9]; localCRS.m22 = winSingleton.trackable.LocalCRS[10]; localCRS.m23 = winSingleton.trackable.LocalCRS[11]; + localCRS.m30 = winSingleton.trackable.LocalCRS[12]; localCRS.m31 = winSingleton.trackable.LocalCRS[13]; localCRS.m32 = winSingleton.trackable.LocalCRS[14]; localCRS.m33 = winSingleton.trackable.LocalCRS[15]; + winSingleton.local_pos = localCRS.GetPosition(); + winSingleton.local_rot = localCRS.rotation.eulerAngles; + } + + } + + public static void ShowWindow(ARFNodeWorldAnchor worldAnchorNode) + { + Type inspectorType = Type.GetType("UnityEditor.InspectorWindow,UnityEditor.dll"); + winSingleton = GetWindow("Element Editor", true, inspectorType); + winSingleton.type = GraphEditorType.WORLDANCHOR; + + winSingleton.trackable = null; + winSingleton.worldAnchor = null; + winSingleton.worldLink = null; + + winSingleton.trackableNode = null; + winSingleton.worldAnchorNode = null; + winSingleton.worldLinkEdge = null; + + winSingleton.worldAnchorNode = worldAnchorNode; + winSingleton.worldAnchor = worldAnchorNode.worldAnchor; + + winSingleton.local_size = new Vector3((float)winSingleton.worldAnchor.WorldAnchorSize[0], (float)winSingleton.worldAnchor.WorldAnchorSize[1], (float)winSingleton.worldAnchor.WorldAnchorSize[2]); + if (winSingleton.worldAnchor.LocalCRS.Count == 16) + { + Matrix4x4 localCRS = new Matrix4x4(); + localCRS.m00 = winSingleton.worldAnchor.LocalCRS[0]; localCRS.m01 = winSingleton.worldAnchor.LocalCRS[1]; localCRS.m02 = winSingleton.worldAnchor.LocalCRS[2]; localCRS.m03 = winSingleton.worldAnchor.LocalCRS[3]; + localCRS.m10 = winSingleton.worldAnchor.LocalCRS[4]; localCRS.m11 = winSingleton.worldAnchor.LocalCRS[5]; localCRS.m12 = winSingleton.worldAnchor.LocalCRS[6]; localCRS.m13 = winSingleton.worldAnchor.LocalCRS[7]; + localCRS.m20 = winSingleton.worldAnchor.LocalCRS[8]; localCRS.m21 = winSingleton.worldAnchor.LocalCRS[9]; localCRS.m22 = winSingleton.worldAnchor.LocalCRS[10]; localCRS.m23 = winSingleton.worldAnchor.LocalCRS[11]; + localCRS.m30 = winSingleton.worldAnchor.LocalCRS[12]; localCRS.m31 = winSingleton.worldAnchor.LocalCRS[13]; localCRS.m32 = winSingleton.worldAnchor.LocalCRS[14]; localCRS.m33 = winSingleton.worldAnchor.LocalCRS[15]; + winSingleton.local_pos = localCRS.GetPosition(); + winSingleton.local_rot = localCRS.rotation.eulerAngles; + } + } + + public static void ShowWindow(ARFEdgeLink graphEdge) + { + Type inspectorType = Type.GetType("UnityEditor.InspectorWindow,UnityEditor.dll"); + winSingleton = GetWindow("Element Editor", true, inspectorType); + winSingleton.type = GraphEditorType.WORLDLINK; + + winSingleton.trackable = null; + winSingleton.worldAnchor = null; + winSingleton.worldLink = null; + + winSingleton.trackableNode = null; + winSingleton.worldAnchorNode = null; + winSingleton.worldLinkEdge = null; + + winSingleton.worldLinkEdge = graphEdge; + winSingleton.worldLink = graphEdge.worldLink; + + if (winSingleton.worldLink.Transform.Count == 16) + { + Matrix4x4 localCRS = new Matrix4x4(); + localCRS.m00 = winSingleton.worldLink.Transform[0]; localCRS.m01 = winSingleton.worldLink.Transform[1]; localCRS.m02 = winSingleton.worldLink.Transform[2]; localCRS.m03 = winSingleton.worldLink.Transform[3]; + localCRS.m10 = winSingleton.worldLink.Transform[4]; localCRS.m11 = winSingleton.worldLink.Transform[5]; localCRS.m12 = winSingleton.worldLink.Transform[6]; localCRS.m13 = winSingleton.worldLink.Transform[7]; + localCRS.m20 = winSingleton.worldLink.Transform[8]; localCRS.m21 = winSingleton.worldLink.Transform[9]; localCRS.m22 = winSingleton.worldLink.Transform[10]; localCRS.m23 = winSingleton.worldLink.Transform[11]; + localCRS.m30 = winSingleton.worldLink.Transform[12]; localCRS.m31 = winSingleton.worldLink.Transform[13]; localCRS.m32 = winSingleton.worldLink.Transform[14]; localCRS.m33 = winSingleton.worldLink.Transform[15]; + winSingleton.local_pos = localCRS.GetPosition(); + winSingleton.local_rot = localCRS.rotation.eulerAngles; + } + } + + public void OnGUI() + { + scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.ExpandWidth(true)); + + //style for copyrights label (left aligned) + var leftStyle = GUI.skin.GetStyle("Label"); + leftStyle.alignment = TextAnchor.UpperLeft; + + GUILayout.Label("Augmented Reality Framework", leftStyle); + GUILayout.Label("Copyright (C) 2024, ETSI (BSD 3-Clause License)", leftStyle); + + //separator line + Rect rect = EditorGUILayout.GetControlRect(false, 1); + EditorGUI.DrawRect(rect, Color.gray); + + switch (type) + { + case GraphEditorType.WORLDLINK: + BuildWorldLinkUI(); + break; + case GraphEditorType.TRACKABLE: + BuildTrackableUI(); + break; + case GraphEditorType.WORLDANCHOR: + BuildWorldAnchorUI(); + break; + default: + break; + } + + EditorGUILayout.EndScrollView(); + } + + //BUILD UI FOR MODIYING THE WORLDANCHOR + private void BuildWorldAnchorUI() + { + if (worldAnchor != null) + { + + // + //HEADER + // + + //anchor icon + EditorGUILayout.BeginHorizontal(); + Texture anchorImage = (Texture)AssetDatabase.LoadAssetAtPath("Packages/etsi.isg.arf.worldstorage/Editor/Images/anchor.png", typeof(Texture)); + GUI.backgroundColor = WorldStorageWindow.arfColors[8]; + GUILayout.Box(anchorImage, GUILayout.Width(40), GUILayout.Height(40)); + + //anchor label + EditorGUILayout.BeginVertical(GUILayout.Height(50)); + GUILayout.FlexibleSpace(); + EditorGUILayout.LabelField("WORLD ANCHOR", EditorStyles.boldLabel); + GUILayout.FlexibleSpace(); + EditorGUILayout.EndVertical(); + EditorGUILayout.EndHorizontal(); + + //separator line + var rect = EditorGUILayout.BeginHorizontal(GUILayout.Height(10)); + DrawUILine(new Color(1, 0.7f, 0, 0.9f), 5, 5); + EditorGUILayout.EndHorizontal(); + + if (worldAnchorNode.titleContainer.Contains(worldAnchorNode.savedIcon)) + { + //the icon to add if the node does not correspond to an element in the server + Texture2D warningImage = (Texture2D)AssetDatabase.LoadAssetAtPath("Packages/etsi.isg.arf.worldstorage/Editor/Images/warning.png", typeof(Texture2D)); + + GUI.backgroundColor = Color.clear; + GUILayout.BeginHorizontal(); + GUILayout.Box(warningImage, GUILayout.Width(27), GUILayout.Height(27)); + GUILayout.Label("This element is not synchronized with the World Storage!", EditorStyles.whiteBoldLabel); + + GUILayout.EndHorizontal(); + } + + // + //ELEMENT PARAMETERS + // + + EditorGUI.BeginChangeCheck(); + + //uuid + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("UUID ", EditorStyles.boldLabel, GUILayout.Width(50)); + if (!SaveInfo.instance.nodePositions.ContainsKey(worldAnchor.UUID.ToString())) + { + EditorGUILayout.LabelField("None yet (element not yet saved in the server)"); + } + else + { + EditorGUILayout.SelectableLabel(worldAnchor.UUID.ToString(), EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); + } + EditorGUILayout.EndHorizontal(); + + GUI.backgroundColor = Color.white; + + //name + EditorGUILayout.BeginHorizontal(); + EditorGUI.BeginChangeCheck(); + EditorGUILayout.LabelField("Name ", EditorStyles.boldLabel, GUILayout.Width(50)); + worldAnchor.Name = EditorGUILayout.DelayedTextField(worldAnchor.Name); + if (EditorGUI.EndChangeCheck()) + { + worldAnchorNode.title = worldAnchor.Name; + } + EditorGUILayout.EndHorizontal(); + + //unit system + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Unit ", EditorStyles.boldLabel, GUILayout.Width(50)); + worldAnchor.Unit = (UnitSystem)EditorGUILayout.EnumPopup(worldAnchor.Unit); + EditorGUILayout.EndHorizontal(); + + //style for sublabels (right aligned) + var rightStyle = GUI.skin.GetStyle("Label"); + rightStyle.alignment = TextAnchor.UpperRight; + + //size + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Size ", EditorStyles.boldLabel, GUILayout.Width(50)); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Width", rightStyle, GUILayout.Width(50)); + local_size[0] = EditorGUILayout.DelayedFloatField(local_size[0]); + EditorGUILayout.LabelField("Length", rightStyle, GUILayout.Width(50)); + local_size[1] = EditorGUILayout.DelayedFloatField(local_size[1]); + EditorGUILayout.LabelField("Depth", rightStyle, GUILayout.Width(50)); + local_size[2] = EditorGUILayout.DelayedFloatField(local_size[2]); + EditorGUILayout.EndHorizontal(); + + //localCRS + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Local CRS ", EditorStyles.boldLabel); + EditorGUILayout.EndHorizontal(); + //position + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Position ", GUILayout.Width(60)); + EditorGUILayout.LabelField("X", rightStyle, GUILayout.Width(15)); + local_pos[0] = EditorGUILayout.DelayedFloatField(local_pos[0]); + EditorGUILayout.LabelField("Y", rightStyle, GUILayout.Width(15)); + local_pos[1] = EditorGUILayout.DelayedFloatField(local_pos[1]); + EditorGUILayout.LabelField("Z", rightStyle, GUILayout.Width(15)); + local_pos[2] = EditorGUILayout.DelayedFloatField(local_pos[2]); + EditorGUILayout.EndHorizontal(); + //rotation + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Rotation ", GUILayout.Width(60)); + EditorGUILayout.LabelField("X", rightStyle, GUILayout.Width(15)); + local_rot[0] = EditorGUILayout.DelayedFloatField(local_rot[0]); + EditorGUILayout.LabelField("Y", rightStyle, GUILayout.Width(15)); + local_rot[1] = EditorGUILayout.DelayedFloatField(local_rot[1]); + EditorGUILayout.LabelField("Z", rightStyle, GUILayout.Width(15)); + local_rot[2] = EditorGUILayout.DelayedFloatField(local_rot[2]); + EditorGUILayout.EndHorizontal(); + + //keyvaluetags=================================================================================================TOBEMODIFIED + /*DrawUILine(Color.gray, 1, 1); + EditorGUILayout.BeginHorizontal(); + GUILayout.Label("Tags ", EditorStyles.boldLabel); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginVertical(); + Dictionary> tempPairs = worldAnchor.KeyvalueTags; + EditorGUILayout.BeginHorizontal(); + m_newKey = GUILayout.TextField(m_newKey, GUILayout.Width(300)); + if (GUILayout.Button("Add Key")) + { + if (m_newKey != "") + { + List emptyList = new List(); + worldAnchor.KeyvalueTags.Add(m_newKey, emptyList); + m_newKey = ""; + } + } + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + //iterator on m_newValues + int j = 0; + foreach (KeyValuePair> entry in tempPairs) + { + EditorGUILayout.BeginHorizontal(); + GUILayout.Label(entry.Key); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("x", GUILayout.Width(18), GUILayout.Height(18))) + { + worldAnchor.KeyvalueTags.Remove(entry.Key); + m_newValues[j] = ""; + } + EditorGUILayout.EndHorizontal(); + + + EditorGUILayout.BeginHorizontal(); + List tempValues = entry.Value; + foreach (string value in tempValues) + { + GUILayout.Label(value); + + if (GUILayout.Button("x", GUILayout.Width(18), GUILayout.Height(18))) + { + tempValues.Remove(value); + worldAnchor.KeyvalueTags[entry.Key] = tempValues; + } + } + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + if (m_newValues.Count < j + 1) + { + string value = ""; + m_newValues.Add(value); + } + m_newValues[j] = GUILayout.TextField(m_newValues[j], GUILayout.Width(200)); + if (GUILayout.Button("Add Value")) + { + if (m_newValues[j] != "") + { + List valueList = entry.Value; + valueList.Add(m_newValues[j]); + worldAnchor.KeyvalueTags[entry.Key] = valueList; + m_newValues[j] = ""; + } + } + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + + j++; + } + EditorGUILayout.EndVertical();*/ + //keyvaluetags=================================================================================================TOBEMODIFIED + + + //Actions when the ui fields have been changed + if (EditorGUI.EndChangeCheck()) + { + // + Matrix4x4 localCRS = Matrix4x4.TRS(local_pos, Quaternion.Euler(local_rot), Vector3.one); + Transform3D localCRSasFloat = new Transform3D + { + localCRS.m00, localCRS.m01, localCRS.m02, localCRS.m03, + localCRS.m10, localCRS.m11, localCRS.m12, localCRS.m13, + localCRS.m20, localCRS.m21, localCRS.m22, localCRS.m23, + localCRS.m30, localCRS.m31, localCRS.m32, localCRS.m33, + }; + worldAnchor.LocalCRS = localCRSasFloat; + + Size localSizeAsFloat = new Size + { + local_size.x, local_size.y, local_size.z + }; + worldAnchor.WorldAnchorSize = localSizeAsFloat; + + if (SaveInfo.instance.nodePositions.ContainsKey(worldAnchor.UUID.ToString()) && (!SaveInfo.instance.elemsToUpdate.Contains(worldAnchor.UUID.ToString()))) + { + SaveInfo.instance.elemsToUpdate.Add(worldAnchor.UUID.ToString()); + } + worldAnchorNode.MarkUnsaved(); + } + + // + //FOOTER + // + //GUILayout.FlexibleSpace(); + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + + var originalColor = GUI.backgroundColor; + + + //reload button + GUI.backgroundColor = Color.yellow; + if (GUILayout.Button("Reload")) + { + //lose focus of fields otherwise the selected field won't updaate + EditorGUI.FocusTextInControl(null); + if (SaveInfo.instance.nodePositions.ContainsKey(worldAnchor.UUID.ToString())) + { + if (SaveInfo.instance.elemsToUpdate.Contains(worldAnchor.UUID.ToString()) && EditorUtility.DisplayDialog("Reset elements", "Are you sure you want to lose all your changes ?", "Yes", "No")) + { + WorldAnchorRequest.GetWorldAnchorAsync(SaveInfo.instance.worldStorageServer, worldAnchor.UUID, (response) => + { + worldAnchor = + worldAnchorNode.worldAnchor = worldAnchor; + ShowWindow(worldAnchorNode); + }); + } + } + else + { + if (EditorUtility.DisplayDialog("Reset elements", "Are you sure you want to lose all your changes ?", "Yes", "No")) + { + //generate the worldAnchor attributes + Transform3D localCRS = new Transform3D(); + for (int i = 0; i < 15; i++) + { + localCRS.Add(0); + } + localCRS.Add(1); + + Size worldAnchorSize = new Size(); + for (int i = 0; i < 3; i++) + { + worldAnchorSize.Add(0); + } + worldAnchor = new WorldAnchor("DefaultWorldAnchor") + { + UUID = Guid.NewGuid(), + CreatorUUID = Guid.Parse(SaveInfo.instance.worldStorageUser.UUID), + LocalCRS = localCRS, + Unit = UnitSystem.CM, + WorldAnchorSize = worldAnchorSize, + KeyvalueTags = new KeyvalueTagList() + }; + worldAnchorNode.worldAnchor = worldAnchor; + ShowWindow(worldAnchorNode); + } + } + } + + // save button + GUI.backgroundColor = Color.green; + if (GUILayout.Button("Save")) + { + System.Guid _creator = Guid.NewGuid(); // System.Guid.Parse(WorldStorageWindow.WorldStorageWindowSingleton.worldStorageUser.UUID); + if (SaveInfo.instance.nodePositions.ContainsKey(worldAnchor.UUID.ToString())) + { + if (SaveInfo.instance.elemsToUpdate.Contains(worldAnchor.UUID.ToString())) + { + WorldAnchorRequest.UpdateWorldAnchorAsync(SaveInfo.instance.worldStorageServer, worldAnchor, (response) => + { + SaveInfo.instance.elemsToUpdate.Remove(worldAnchor.UUID.ToString()); + }); + } + } + else + { + var posX = new Collection(); + posX.Add(worldAnchorNode.GetPosition().x.ToString()); + var posY = new Collection(); + posY.Add(worldAnchorNode.GetPosition().y.ToString()); + + WorldAnchor worldAnchor = worldAnchorNode.worldAnchor; + worldAnchor.KeyvalueTags["unityAuthoringPosX"] = posX; + worldAnchor.KeyvalueTags["unityAuthoringPosY"] = posY; + + WorldAnchorRequest.CreateWorldAnchorAsync(SaveInfo.instance.worldStorageServer, worldAnchor, (response) => + { + String uuid = response.result; + + //change the uuid in its edges, if there is a new edge to be added in the world storage it needs to have the correct uuid + uuid = uuid.Replace("\"", ""); + foreach (ARFEdgeLink edge in worldAnchorNode.portIn.connections) + { + edge.worldLink.UUIDTo = Guid.Parse(uuid); + } + foreach (ARFEdgeLink edge in worldAnchorNode.portOut.connections) + { + edge.worldLink.UUIDFrom = Guid.Parse(uuid); + } + worldAnchorNode.worldAnchor.UUID = Guid.Parse(uuid); + worldAnchorNode.GUID = uuid; + worldAnchorNode.title = worldAnchor.Name; + + //Add the newly saved World Anchor to the SaveInfo singleton + Rect trackPos = new(worldAnchorNode.GetPosition().x, worldAnchorNode.GetPosition().y, 135, 77); + SaveInfo.instance.nodePositions[uuid] = trackPos; + }); + } + worldAnchorNode.MarkSaved(); + } + GUILayout.Space(10); + EditorGUILayout.EndHorizontal(); + GUILayout.Space(10); + + GUI.backgroundColor = originalColor; + + + } + } + + private void BuildTrackableUI() + { + if (trackable != null) + { + // + //HEADER + // + + //trackable icon + EditorGUILayout.BeginHorizontal(); + Texture trackImage = (Texture)AssetDatabase.LoadAssetAtPath("Packages/etsi.isg.arf.worldstorage/Editor/Images/trackable.png", typeof(Texture)); + GUI.backgroundColor = WorldStorageWindow.arfColors[7]; + GUILayout.Box(trackImage, GUILayout.Width(40), GUILayout.Height(40)); + + //trackable label + EditorGUILayout.BeginVertical(GUILayout.Height(50)); + GUILayout.FlexibleSpace(); + EditorGUILayout.LabelField("TRACKABLE", EditorStyles.boldLabel); + GUILayout.FlexibleSpace(); + EditorGUILayout.EndVertical(); + EditorGUILayout.EndHorizontal(); + + //separator line + var rect = EditorGUILayout.BeginHorizontal(GUILayout.Height(10)); + DrawUILine(new Color(1, 0.31f, 0.31f, 0.9f), 5, 0); + EditorGUILayout.EndHorizontal(); + + if (trackableNode.titleContainer.Contains(trackableNode.savedIcon)) + { + //the icon to add if the node does not correspond to an element in the server + Texture2D warningImage = (Texture2D)AssetDatabase.LoadAssetAtPath("Packages/etsi.isg.arf.worldstorage/Editor/Images/warning.png", typeof(Texture2D)); + + GUI.backgroundColor = Color.clear; + GUILayout.BeginHorizontal(); + GUILayout.Box(warningImage, GUILayout.Width(27), GUILayout.Height(27)); + GUILayout.Label("This element is not synchronized with the World Storage!", EditorStyles.whiteBoldLabel); + GUILayout.EndHorizontal(); + } + + // + //ELEMENT PARAMETERS + // + + EditorGUI.BeginChangeCheck(); + + //uuid + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("UUID ", EditorStyles.boldLabel, GUILayout.Width(50)); + if (!SaveInfo.instance.nodePositions.ContainsKey(trackable.UUID.ToString())) + { + EditorGUILayout.LabelField("None yet (element not yet saved in the server)"); + } + else + { + EditorGUILayout.SelectableLabel(trackable.UUID.ToString(), EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); + } + EditorGUILayout.EndHorizontal(); + + GUI.backgroundColor = Color.white; + + //name + EditorGUILayout.BeginHorizontal(); + EditorGUI.BeginChangeCheck(); + EditorGUILayout.LabelField("Name ", EditorStyles.boldLabel, GUILayout.Width(50)); + trackable.Name = EditorGUILayout.DelayedTextField(trackable.Name); + if (EditorGUI.EndChangeCheck()) + { + trackableNode.title = trackable.Name; + } + EditorGUILayout.EndHorizontal(); + + //trackable's type + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Type ", EditorStyles.boldLabel, GUILayout.Width(50)); + trackable.TrackableType = (TrackableType)EditorGUILayout.EnumPopup(trackable.TrackableType); + EditorGUILayout.EndHorizontal(); + + //unit system + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Unit ", EditorStyles.boldLabel, GUILayout.Width(50)); + trackable.Unit = (UnitSystem)EditorGUILayout.EnumPopup(trackable.Unit); + EditorGUILayout.EndHorizontal(); + + //style for sublabels (right aligned) + var rightStyle = GUI.skin.GetStyle("Label"); + rightStyle.alignment = TextAnchor.UpperRight; + + //size + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Size ", EditorStyles.boldLabel, GUILayout.Width(50)); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Width", rightStyle, GUILayout.Width(50)); + local_size[0] = EditorGUILayout.DelayedFloatField(local_size[0]); + EditorGUILayout.LabelField("Length", rightStyle, GUILayout.Width(50)); + local_size[1] = EditorGUILayout.DelayedFloatField(local_size[1]); + EditorGUILayout.LabelField("Depth", rightStyle, GUILayout.Width(50)); + local_size[2] = EditorGUILayout.DelayedFloatField(local_size[2]); + EditorGUILayout.EndHorizontal(); + + //localCRS + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Local CRS ", EditorStyles.boldLabel); + EditorGUILayout.EndHorizontal(); + //position + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Position ", GUILayout.Width(60)); + EditorGUILayout.LabelField("X", rightStyle, GUILayout.Width(15)); + local_pos[0] = EditorGUILayout.DelayedFloatField(local_pos[0]); + EditorGUILayout.LabelField("Y", rightStyle, GUILayout.Width(15)); + local_pos[1] = EditorGUILayout.DelayedFloatField(local_pos[1]); + EditorGUILayout.LabelField("Z", rightStyle, GUILayout.Width(15)); + local_pos[2] = EditorGUILayout.DelayedFloatField(local_pos[2]); + EditorGUILayout.EndHorizontal(); + //rotation + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Rotation ", GUILayout.Width(60)); + EditorGUILayout.LabelField("X", rightStyle, GUILayout.Width(15)); + local_rot[0] = EditorGUILayout.DelayedFloatField(local_rot[0]); + EditorGUILayout.LabelField("Y", rightStyle, GUILayout.Width(15)); + local_rot[1] = EditorGUILayout.DelayedFloatField(local_rot[1]); + EditorGUILayout.LabelField("Z", rightStyle, GUILayout.Width(15)); + local_rot[2] = EditorGUILayout.DelayedFloatField(local_rot[2]); + EditorGUILayout.EndHorizontal(); + + //encodingInofrmation + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Trackable Information ", EditorStyles.boldLabel); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Format ", GUILayout.Width(50)); + trackable.TrackableEncodingInformation.DataFormat = (EncodingInformationStructureDataFormat)EditorGUILayout.EnumPopup(trackable.TrackableEncodingInformation.DataFormat); + EditorGUILayout.LabelField("Version ", GUILayout.Width(50)); + float floatVersion; + if (trackable.TrackableEncodingInformation.Version != null) + { + floatVersion = EditorGUILayout.DelayedFloatField(WorldStorageRequest.FloatParse(trackable.TrackableEncodingInformation.Version)); + } + else + { + floatVersion = EditorGUILayout.DelayedFloatField(0); + } + trackable.TrackableEncodingInformation.Version = floatVersion.ToString(); + EditorGUILayout.EndHorizontal(); + + /*//trackable payload + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Trackable Payload ", EditorStyles.boldLabel, GUILayout.Width(140)); + EditorGUILayout.LabelField("==============================================================================="); + EditorGUILayout.EndHorizontal();*/ + + //keyvaluetags=================================================================================================TOBEMODIFIED + /*EditorGUILayout.BeginHorizontal(); + GUILayout.Label("Tags ", EditorStyles.boldLabel); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginVertical(); + Dictionary> tempPairs = trackable.KeyvalueTags; + EditorGUILayout.BeginHorizontal(); + m_newKey = GUILayout.TextField(m_newKey, GUILayout.Width(300)); + if (GUILayout.Button("Add Key")) + { + if (m_newKey != "") + { + List emptyList = new List(); + trackable.KeyvalueTags.Add(m_newKey, emptyList); + m_newKey = ""; + } + } + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + //iterator on m_newValues + int j = 0; + foreach (KeyValuePair> entry in tempPairs) + { + DrawUILine(Color.gray, 1, 1); + EditorGUILayout.BeginHorizontal(); + GUILayout.Label(entry.Key); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("x", GUILayout.Width(18), GUILayout.Height(18))) + { + trackable.KeyvalueTags.Remove(entry.Key); + m_newValues[j] = ""; + } + EditorGUILayout.EndHorizontal(); + + + EditorGUILayout.BeginHorizontal(); + List tempValues = entry.Value; + foreach (string value in tempValues) + { + GUILayout.Label(value); + + if (GUILayout.Button("x", GUILayout.Width(18), GUILayout.Height(18))) + { + tempValues.Remove(value); + trackable.KeyvalueTags[entry.Key] = tempValues; + } + } + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + if (m_newValues.Count < j + 1) + { + string value = ""; + m_newValues.Add(value); + } + m_newValues[j] = GUILayout.TextField(m_newValues[j], GUILayout.Width(200)); + if (GUILayout.Button("Add Value")) + { + if (m_newValues[j] != "") + { + List valueList = entry.Value; + valueList.Add(m_newValues[j]); + trackable.KeyvalueTags[entry.Key] = valueList; + m_newValues[j] = ""; + } + } + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + + j++; + } + EditorGUILayout.EndVertical();*//*EditorGUILayout.BeginHorizontal(); + GUILayout.Label("Tags ", EditorStyles.boldLabel); + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginVertical(); + Dictionary> tempPairs = trackable.KeyvalueTags; + EditorGUILayout.BeginHorizontal(); + m_newKey = GUILayout.TextField(m_newKey, GUILayout.Width(300)); + if (GUILayout.Button("Add Key")) + { + if (m_newKey != "") + { + List emptyList = new List(); + trackable.KeyvalueTags.Add(m_newKey, emptyList); + m_newKey = ""; + } + } + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + //iterator on m_newValues + int j = 0; + foreach (KeyValuePair> entry in tempPairs) + { + DrawUILine(Color.gray, 1, 1); + EditorGUILayout.BeginHorizontal(); + GUILayout.Label(entry.Key); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("x", GUILayout.Width(18), GUILayout.Height(18))) + { + trackable.KeyvalueTags.Remove(entry.Key); + m_newValues[j] = ""; + } + EditorGUILayout.EndHorizontal(); + + + EditorGUILayout.BeginHorizontal(); + List tempValues = entry.Value; + foreach (string value in tempValues) + { + GUILayout.Label(value); + + if (GUILayout.Button("x", GUILayout.Width(18), GUILayout.Height(18))) + { + tempValues.Remove(value); + trackable.KeyvalueTags[entry.Key] = tempValues; + } + } + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + if (m_newValues.Count < j + 1) + { + string value = ""; + m_newValues.Add(value); + } + m_newValues[j] = GUILayout.TextField(m_newValues[j], GUILayout.Width(200)); + if (GUILayout.Button("Add Value")) + { + if (m_newValues[j] != "") + { + List valueList = entry.Value; + valueList.Add(m_newValues[j]); + trackable.KeyvalueTags[entry.Key] = valueList; + m_newValues[j] = ""; + } + } + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + + j++; + } + EditorGUILayout.EndVertical();*/ + //keyvaluetags=================================================================================================TOBEMODIFIED + + + //Actions when the ui fields have been changed + if (EditorGUI.EndChangeCheck()) + { + // + Matrix4x4 localCRS = Matrix4x4.TRS(local_pos, Quaternion.Euler(local_rot), Vector3.one); + Transform3D localCRSasFloat = new Transform3D + { + localCRS.m00, localCRS.m01, localCRS.m02, localCRS.m03, + localCRS.m10, localCRS.m11, localCRS.m12, localCRS.m13, + localCRS.m20, localCRS.m21, localCRS.m22, localCRS.m23, + localCRS.m30, localCRS.m31, localCRS.m32, localCRS.m33, + }; + trackable.LocalCRS = localCRSasFloat; + + Size localSizeAsFloat = new Size + { + local_size.x, local_size.y, local_size.z + }; + trackable.TrackableSize = localSizeAsFloat; + + if (SaveInfo.instance.nodePositions.ContainsKey(trackable.UUID.ToString()) && (!SaveInfo.instance.elemsToUpdate.Contains(trackable.UUID.ToString()))) + { + SaveInfo.instance.elemsToUpdate.Add(trackable.UUID.ToString()); + } + trackableNode.MarkUnsaved(); + } + + // + //FOOTER + // + GUILayout.FlexibleSpace(); + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + + var originalColor = GUI.backgroundColor; + + //reload button + GUI.backgroundColor = Color.yellow; + if (GUILayout.Button("Reload")) + { + //lose focus of fields otherwise the selected field won't updaate + EditorGUI.FocusTextInControl(null); + if (SaveInfo.instance.nodePositions.ContainsKey(trackable.UUID.ToString())) + { + if (SaveInfo.instance.elemsToUpdate.Contains(trackable.UUID.ToString()) && EditorUtility.DisplayDialog("Reset elements", "Are you sure you want to lose all your changes ?", "Yes", "No")) + { + TrackableRequest.GetTrackableAsync(SaveInfo.instance.worldStorageServer, trackable.UUID, (response) => + { + trackable = response.result; + trackableNode.trackable = trackable; + ShowWindow(trackableNode); + }); + } + } + else + { + if (EditorUtility.DisplayDialog("Reset elements", "Are you sure you want to lose all your changes ?", "Yes", "No")) + { + //generate the Trackables's attributes + EncodingInformationStructure trackableEncodingInformation = new EncodingInformationStructure() + { + DataFormat = EncodingInformationStructureDataFormat.OTHER, + Version = "0" + }; + + Transform3D localCRS = new Transform3D(); + for (int i = 0; i < 15; i++) + { + localCRS.Add(0); + } + localCRS.Add(1); + + Size trackableSize = new Size(); + for (int i = 0; i < 3; i++) + { + trackableSize.Add(0); + } + + Trackable trackable = new Trackable("DefaultTrackable") + { + UUID = Guid.NewGuid(), + CreatorUUID = Guid.Parse(SaveInfo.instance.worldStorageUser.UUID), + TrackableType = TrackableType.OTHER, + TrackableEncodingInformation = trackableEncodingInformation, + TrackablePayload = new byte[64], + LocalCRS = localCRS, + Unit = UnitSystem.CM, + Confidence = 0, + TrackableSize = trackableSize, + KeyvalueTags = new KeyvalueTagList() + }; + trackableNode.trackable = trackable; + ShowWindow(trackableNode); + } + } + } + + //save button + GUI.backgroundColor = Color.green; + if (GUILayout.Button("Save")) + { + if (SaveInfo.instance.nodePositions.ContainsKey(trackable.UUID.ToString())) + { + if (SaveInfo.instance.elemsToUpdate.Contains(trackable.UUID.ToString())) + { + TrackableRequest.UpdateTrackableAsync(SaveInfo.instance.worldStorageServer, trackable, (response) => + { + SaveInfo.instance.elemsToUpdate.Remove(trackable.UUID.ToString()); + }); + } + } + else + { + var posX = new Collection(); + posX.Add(trackableNode.GetPosition().x.ToString()); + var posY = new Collection(); + posY.Add(trackableNode.GetPosition().y.ToString()); + Trackable trackable = trackableNode.trackable; + trackable.KeyvalueTags["unityAuthoringPosX"] = posX; + trackable.KeyvalueTags["unityAuthoringPosY"] = posY; + TrackableRequest.CreateTrackableAsync(SaveInfo.instance.worldStorageServer, trackable, (response) => + { + String uuid = response.result; + + //change the uuid in its edges, if there is a new edge to be added in the world storage it needs to have the correct uuid + uuid = uuid.Replace("\"", ""); + foreach (ARFEdgeLink edge in trackableNode.portIn.connections) + { + edge.worldLink.UUIDTo = Guid.Parse(uuid); + } + foreach (ARFEdgeLink edge in trackableNode.portOut.connections) + { + edge.worldLink.UUIDFrom = Guid.Parse(uuid); + } + trackableNode.trackable.UUID = Guid.Parse(uuid); + trackableNode.GUID = uuid; + trackableNode.title = trackable.Name; + + //Add the newly saved Trackable to the SaveInfo singleton + Rect trackPos = new(trackableNode.GetPosition().x, trackableNode.GetPosition().y, 135, 77); + SaveInfo.instance.nodePositions[uuid] = trackPos; + }); + } + trackableNode.MarkSaved(); + } + GUILayout.Space(10); + EditorGUILayout.EndHorizontal(); + GUILayout.Space(10); + + GUI.backgroundColor = originalColor; + + + } + } + + private void BuildWorldLinkUI() + { + if (worldLink != null) + { + // + //HEADER + // + + //world link icon + EditorGUILayout.BeginHorizontal(); + Texture linkImage = (Texture)AssetDatabase.LoadAssetAtPath("Packages/etsi.isg.arf.worldstorage/Editor/Images/link.png", typeof(Texture)); + GUI.backgroundColor = WorldStorageWindow.arfColors[9]; + GUILayout.Box(linkImage, GUILayout.Width(40), GUILayout.Height(40)); + + //world link label + EditorGUILayout.BeginVertical(GUILayout.Height(50)); + GUILayout.FlexibleSpace(); + EditorGUILayout.LabelField("WORLD LINK", EditorStyles.boldLabel); + GUILayout.FlexibleSpace(); + EditorGUILayout.EndVertical(); + EditorGUILayout.EndHorizontal(); + + //separator line + var rect = EditorGUILayout.BeginHorizontal(GUILayout.Height(10)); + DrawUILine(new Color(0.66f, 0.39f, 1, 0.77f), 5, 5); + EditorGUILayout.EndHorizontal(); + + if (worldLinkEdge.contentContainer.Contains(worldLinkEdge.savedIcon)) + { + //the icon to add if the node does not correspond to an element in the server + Texture2D warningImage = (Texture2D)AssetDatabase.LoadAssetAtPath("Packages/etsi.isg.arf.worldstorage/Editor/Images/warning.png", typeof(Texture2D)); + + GUI.backgroundColor = Color.clear; + GUILayout.BeginHorizontal(); + GUILayout.Box(warningImage, GUILayout.Width(27), GUILayout.Height(27)); + GUILayout.Label("This element is not synchronized with the World Storage!", EditorStyles.whiteBoldLabel); + GUILayout.EndHorizontal(); + } + + //ELEMENT'S ATTRIBUTES + EditorGUI.BeginChangeCheck(); + + GUI.backgroundColor = Color.white; + + //uuid + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("UUID ", EditorStyles.boldLabel, GUILayout.Width(50)); + if (!SaveInfo.instance.linkIds.Contains(worldLink.UUID.ToString())) + { + EditorGUILayout.LabelField("None yet (element not yet saved in the server)"); + } + else + { + EditorGUILayout.SelectableLabel(worldLink.UUID.ToString(), EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); + } + EditorGUILayout.EndHorizontal(); + + //source element + EditorGUILayout.LabelField("Source Element (From element)", EditorStyles.boldLabel); + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(50); + EditorGUILayout.LabelField("Name ", GUILayout.Width(75)); + EditorGUILayout.LabelField(worldLinkEdge.output.node.title); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(50); + EditorGUILayout.LabelField("Type ", GUILayout.Width(75)); + EditorGUILayout.LabelField(worldLink.TypeFrom.ToString(), GUILayout.Width(80)); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(50); + EditorGUILayout.LabelField("UUID ", GUILayout.Width(75)); + if (SaveInfo.instance.nodePositions.ContainsKey(worldLink.UUIDFrom.ToString())) + { + EditorGUILayout.LabelField(worldLink.UUIDFrom.ToString()); + } + else + { + EditorGUILayout.LabelField("no UUID yet (element not yet saved in the server)"); + } + EditorGUILayout.EndHorizontal(); + + //target element + EditorGUILayout.LabelField("Target Element (To element)", EditorStyles.boldLabel); + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(50); + EditorGUILayout.LabelField("Name ", GUILayout.Width(70)); + EditorGUILayout.LabelField(worldLinkEdge.input.node.title); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(50); + EditorGUILayout.LabelField("Type ", GUILayout.Width(70)); + EditorGUILayout.LabelField(worldLink.TypeTo.ToString(), GUILayout.Width(80)); + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(50); + EditorGUILayout.LabelField("UUID ", GUILayout.Width(70)); + if (SaveInfo.instance.nodePositions.ContainsKey(worldLink.UUIDTo.ToString())) + { + EditorGUILayout.LabelField(worldLink.UUIDTo.ToString()); + } + else + { + EditorGUILayout.LabelField("no UUID yet (element not yet saved in the server)"); + } + EditorGUILayout.EndHorizontal(); + + //unit system + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Unit ", EditorStyles.boldLabel, GUILayout.Width(50)); + worldLink.Unit = (UnitSystem)EditorGUILayout.EnumPopup(worldLink.Unit); + EditorGUILayout.EndHorizontal(); + + //style for sublabels (right aligned) + var rightStyle = GUI.skin.GetStyle("Label"); + rightStyle.alignment = TextAnchor.UpperRight; + + //localCRS + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("3D Transform ", EditorStyles.boldLabel); + EditorGUILayout.EndHorizontal(); + //position + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Position ", GUILayout.Width(60)); + EditorGUILayout.LabelField("X", rightStyle, GUILayout.Width(15)); + local_pos[0] = EditorGUILayout.DelayedFloatField(local_pos[0]); + EditorGUILayout.LabelField("Y", rightStyle, GUILayout.Width(15)); + local_pos[1] = EditorGUILayout.DelayedFloatField(local_pos[1]); + EditorGUILayout.LabelField("Z", rightStyle, GUILayout.Width(15)); + local_pos[2] = EditorGUILayout.DelayedFloatField(local_pos[2]); + EditorGUILayout.EndHorizontal(); + //rotation + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Rotation ", GUILayout.Width(60)); + EditorGUILayout.LabelField("X", rightStyle, GUILayout.Width(15)); + local_rot[0] = EditorGUILayout.DelayedFloatField(local_rot[0]); + EditorGUILayout.LabelField("Y", rightStyle, GUILayout.Width(15)); + local_rot[1] = EditorGUILayout.DelayedFloatField(local_rot[1]); + EditorGUILayout.LabelField("Z", rightStyle, GUILayout.Width(15)); + local_rot[2] = EditorGUILayout.DelayedFloatField(local_rot[2]); + EditorGUILayout.EndHorizontal(); + + //Actions when the ui fields have been changed + if (EditorGUI.EndChangeCheck()) + { + // + Matrix4x4 localCRS = Matrix4x4.TRS(local_pos, Quaternion.Euler(local_rot), Vector3.one); + Transform3D localCRSasFloat = new Transform3D + { + localCRS.m00, localCRS.m01, localCRS.m02, localCRS.m03, + localCRS.m10, localCRS.m11, localCRS.m12, localCRS.m13, + localCRS.m20, localCRS.m21, localCRS.m22, localCRS.m23, + localCRS.m30, localCRS.m31, localCRS.m32, localCRS.m33, + }; + worldLink.Transform = localCRSasFloat; + + if (SaveInfo.instance.linkIds.Contains(worldLink.UUID.ToString()) && (!SaveInfo.instance.elemsToUpdate.Contains(worldLink.UUID.ToString()))) + { + SaveInfo.instance.elemsToUpdate.Add(worldLink.UUID.ToString()); + } + worldLinkEdge.MarkUnsaved(); + } + + // + //FOOTER + // + GUILayout.FlexibleSpace(); + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + + var originalColor = GUI.backgroundColor; + + //reload button + GUI.backgroundColor = Color.yellow; + if (GUILayout.Button("Reload")) + { + //lose focus of fields otherwise the selected field won't updaate + EditorGUI.FocusTextInControl(null); + if (SaveInfo.instance.linkIds.Contains(worldLink.UUID.ToString())) + { + if (SaveInfo.instance.elemsToUpdate.Contains(worldLink.UUID.ToString()) && EditorUtility.DisplayDialog("Reset elements", "Are you sure you want to lose all your changes ?", "Yes", "No")) + { + WorldLinkRequest.GetWorldLinkAsync(SaveInfo.instance.worldStorageServer, worldLink.UUID, (response) => + { + worldLink = response.result; + worldLinkEdge.worldLink = worldLink; + ShowWindow(worldLinkEdge); + }); + } + } + else + { + if (EditorUtility.DisplayDialog("Reset elements", "Are you sure you want to lose all your changes ?", "Yes", "No")) + { + Transform3D transform = new Transform3D(); + for (int i = 0; i < 15; i++) + { + transform.Add(0); + } + transform.Add(1); + + worldLink.Transform = transform; + worldLink.Unit = UnitSystem.CM; + ShowWindow(worldLinkEdge); + } + } + } + + //save button + GUI.backgroundColor = Color.green; + if (GUILayout.Button("Save")) + { + //if one of the connected elements is not in the server, you can't save the link + if ((SaveInfo.instance.nodePositions.ContainsKey(worldLink.UUIDTo.ToString()) && SaveInfo.instance.nodePositions.ContainsKey(worldLink.UUIDFrom.ToString()))) + { + if (SaveInfo.instance.linkIds.Contains(worldLink.UUID.ToString())) + { + if (SaveInfo.instance.elemsToUpdate.Contains(worldLink.UUID.ToString())) + { + WorldLinkRequest.UpdateWorldLinkAsync(SaveInfo.instance.worldStorageServer, worldLink, (response) => + { + SaveInfo.instance.elemsToUpdate.Remove(worldLink.UUID.ToString()); + }); + } + } + else + { + WorldLinkRequest.CreateWorldLinkAsync(SaveInfo.instance.worldStorageServer, worldLink, (response) => + { + String uuid = response.result; + + //Add the newly saved WorldLink to the SaveInfo singleton + uuid = uuid.Replace("\"", ""); + worldLink.UUID = Guid.Parse(uuid); + worldLinkEdge.GUID = uuid; + SaveInfo.instance.linkIds.Add(uuid); + }); + } + worldLinkEdge.MarkSaved(); + } + else + { + EditorUtility.DisplayDialog("Error", "You are not able to save this link because at least one of its connected elements is not saved in the World Storage", "Ok"); + } + } + GUILayout.Space(10); + EditorGUILayout.EndHorizontal(); + GUILayout.Space(10); + + } + } + + //utilty method to draw lines + public static void DrawUILine(Color color, int thickness = 2, int padding = 10) + { + Rect r = EditorGUILayout.GetControlRect(GUILayout.Height(padding + thickness)); + r.height = thickness; + r.y += padding / 2; + r.x -= 2; + r.width += 6; + EditorGUI.DrawRect(r, color); + } + + + + + } +} \ No newline at end of file diff --git a/Editor/Scripts/Windows/GraphEditorWindow.cs.meta b/Editor/Scripts/Windows/GraphEditorWindow.cs.meta new file mode 100644 index 0000000..1079749 --- /dev/null +++ b/Editor/Scripts/Windows/GraphEditorWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e219817d65c8b1f40ad85e6185e89e92 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/Windows/TrackableWindow.cs b/Editor/Scripts/Windows/TrackableWindow.cs new file mode 100644 index 0000000..6360d7a --- /dev/null +++ b/Editor/Scripts/Windows/TrackableWindow.cs @@ -0,0 +1,378 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2024 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: June 2024 +// + +#define isDEBUG + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +using UnityEngine; +using UnityEditor; +using TMPro; + +using ETSI.ARF.WorldStorage.REST; +using ETSI.ARF.OpenAPI.WorldStorage; + +namespace ETSI.ARF.WorldStorage.UI +{ + public class TrackableWindow : BaseWindow + { + static public TrackableWindow winSingleton; + + // Trackable params + string UUID = System.Guid.Empty.ToString(); + string customName = "NotDefined"; + string creatorUUID = System.Guid.Empty.ToString(); + double confidence = 0f; + TrackableType type = TrackableType.OTHER; + UnitSystem unit = UnitSystem.CM; + Vector3 trackableSize; + Vector3 localCRS_pos; + Vector3 localCRS_rot; + byte[] trackablePayload = new byte[1] { 0 }; + + //graph params to generate the node + public bool useCoord; + public float nodePosX = 0; + public float nodePosY = 0; + + public TrackableWindow() + { + // init somne stuffs + } + + public static void ShowWindow(WorldStorageServer ws, WorldStorageUser user, string UUID = "") + { + winSingleton = EditorWindow.GetWindow(typeof(TrackableWindow), false, "ETSI ARF - Trackable") as TrackableWindow; + winSingleton.worldStorageServer = ws; + winSingleton.worldStorageUser = user; + if (!string.IsNullOrEmpty(UUID)) + { + winSingleton.saveText = "Update"; + winSingleton.UUID = UUID; + winSingleton.GetParams(); + } + else + { + // Create new one + winSingleton.saveText = "Create"; + winSingleton.AddObject(); + } + } + + public static GameObject GenerateAndUpdateVisual(string UUID, string name, Vector3 pos, Vector3 rot) + { + ETSI.ARF.WorldStorage.UI.Prefabs.WorldStoragePrefabs prefabs; + prefabs = (Prefabs.WorldStoragePrefabs)Resources.Load("ARFPrefabs"); + GameObject arf = GameObject.Find("ARF Visuals"); + GameObject visual = GameObject.Find(UUID); + + if (arf == null) arf = new GameObject("ARF Visuals"); + if (visual == null) + { + visual = SceneAsset.Instantiate(prefabs.trackablePrefab, pos, Quaternion.Euler(rot), arf.transform); // TODO rot + visual.name = UUID; + } + else + { + visual.transform.SetPositionAndRotation(pos, Quaternion.Euler(rot)); + } + visual.transform.Find("Canvas/Text").GetComponent().text = $"Name: { name }\nUUID: { UUID }"; + return visual; + } + + void OnGUI() + { + ori = GUI.backgroundColor; // remember ori color + + gsTest = new GUIStyle("window"); + //gsTest.normal.textColor = WorldStorageWindow.arfColors[0]; + gsTest.fontStyle = FontStyle.Bold; + gsTest.alignment = TextAnchor.UpperLeft; + gsTest.fontSize = 16; + + scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.ExpandWidth(true)); + WorldStorageWindow.DrawCopyright(); + + DrawUIStuffs(); + + EditorGUILayout.EndScrollView(); + + if (GUILayout.Button("Close Window")) + { + Close(); + } + } + + public override void DrawUIStuffs()// Trackable trackable) + { + GUILayout.BeginVertical(); // "Trackable Editor", gsTest); + EditorGUILayout.Space(); + + GUILayout.BeginHorizontal(); + GUI.backgroundColor = WorldStorageWindow.arfColors[7]; + Texture trackableImage = (Texture)AssetDatabase.LoadAssetAtPath("Packages/etsi.isg.arf.worldstorage/Editor/Images/trackable.png", typeof(Texture)); + GUILayout.Box(trackableImage, GUILayout.Width(24), GUILayout.Height(24)); + GUI.backgroundColor = ori; + GUILayout.Label("Trackable Parameters:", EditorStyles.whiteBoldLabel); + GUILayout.EndHorizontal(); + + Rect rect = EditorGUILayout.GetControlRect(false, WorldStorageWindow.lineH); + EditorGUI.DrawRect(rect, WorldStorageWindow.arfColors[7]); + + // + GUILayout.Label("Server: " + worldStorageServer.serverName, EditorStyles.whiteLargeLabel); + GUILayout.Label("User: " + worldStorageUser.userName, EditorStyles.whiteLargeLabel); + EditorGUILayout.Space(); + +#if isDEBUG + GUILayout.Label("UUID: " + UUID, EditorStyles.miniLabel); // readonly + GUILayout.Label("Creator UID: " + creatorUUID, EditorStyles.miniLabel); // readonly + EditorGUILayout.Space(); +#endif + customName = EditorGUILayout.TextField("Name of Trackable:", customName); + EditorGUILayout.Space(); + + // --------------------- + // Toolbar + // --------------------- + EditorGUILayout.BeginHorizontal(); + GUI.backgroundColor = WorldStorageWindow.arfColors[2]; + if (GUILayout.Button(saveText)) + { + Debug.Log("PUT Trackable"); + + if (!string.IsNullOrEmpty(UUID) && UUID != "0" && UUID != System.Guid.Empty.ToString()) + { + Trackable obj = GenerateObject(); + TrackableRequest.UpdateTrackableAsync(worldStorageServer, obj, (response) => + { + UUID = response.result; + UUID = UUID.Trim('"'); //Bugfix: remove " from server return value + + if (WorldStorageWindow.WorldStorageWindowSingleton != null) + { + WorldStorageWindow.WorldStorageWindowSingleton.GetTrackables(); + } + Close(); + }); + } + } + + GUI.backgroundColor = WorldStorageWindow.arfColors[3]; + if (GUILayout.Button("Delete")) + { + if (EditorUtility.DisplayDialog("Delete", "Are you sure you want to delete this Trackable?", "Delete", "Cancel")) + { + Debug.Log("Delete Trackable"); + TrackableRequest.DeleteTrackableAsync(worldStorageServer, Guid.Parse(UUID), (response) => + { + UUID = System.Guid.Empty.ToString(); + customName = "Warning: Object deleted !"; + creatorUUID = System.Guid.Empty.ToString(); + confidence = 0f; + type = TrackableType.OTHER; + unit = UnitSystem.CM; + if (WorldStorageWindow.WorldStorageWindowSingleton != null) + { + WorldStorageWindow.WorldStorageWindowSingleton.GetTrackables(); + } + Close(); + }); + } + } + GUI.backgroundColor = ori; + + GUI.backgroundColor = WorldStorageWindow.arfColors[5]; + if (GUILayout.Button("Generate/Update GameObject")) + { + GenerateAndUpdateVisual(UUID, customName, localCRS_pos, localCRS_rot); + } + GUI.backgroundColor = ori; + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + + // --------------------- + // Params + // --------------------- + type = (TrackableType)EditorGUILayout.EnumPopup("Trackable Type:", type); + unit = (UnitSystem)EditorGUILayout.EnumPopup("Unit System:", unit); + confidence = EditorGUILayout.DoubleField("Confidence:", confidence); + + EditorGUILayout.Space(); + trackableSize = EditorGUILayout.Vector3Field("Trackable Size:", trackableSize); + + EditorGUILayout.Space(); + GUILayout.Label("Local CRS:"); + localCRS_pos = EditorGUILayout.Vector3Field(" Position:", localCRS_pos); + localCRS_rot = EditorGUILayout.Vector3Field(" Rotation:", localCRS_rot); + + EditorGUILayout.Space(); + if (GUILayout.Button("Generate Dummy Payload")) + { + // dummy + trackablePayload = new byte[100]; + for (int i = 0; i < trackablePayload.Length; i++) + { + trackablePayload[i] = (byte)i; + } + } + + // --------------------- + // Keyvalues + // --------------------- + EditorGUILayout.Space(); + groupEnabled = EditorGUILayout.BeginToggleGroup("Optional Parameters:", groupEnabled); + if (keyValuesFixed.Count > 0) + { + OutputKeyValue(0); + OutputKeyValue(1); + OutputKeyValue(2); + } + EditorGUILayout.EndToggleGroup(); + // + GUILayout.EndVertical(); + } + + public override void GetParams() + { + customName = "Requesting information..."; + + TrackableRequest.GetTrackableAsync(worldStorageServer, Guid.Parse(UUID), (response) => + { + Trackable obj = response.result; + customName = obj.Name; + creatorUUID = obj.CreatorUUID.ToString(); + type = obj.TrackableType; + unit = obj.Unit; + confidence = obj.Confidence; + if (obj.TrackableSize.Count == 3) + { + trackableSize = new Vector3((float)obj.TrackableSize[0], (float)obj.TrackableSize[1], (float)obj.TrackableSize[2]); + } + else trackableSize = Vector3.zero; + + if (obj.LocalCRS.Count == 16) + { + Matrix4x4 localCRS = WorldStorageUnityHelper.ConvertETSIARFTransform3DToUnity(obj.LocalCRS); + localCRS_pos = localCRS.GetPosition(); + localCRS_rot = localCRS.rotation.eulerAngles; + } + else + { + localCRS_pos = Vector3.zero; + localCRS_rot = Vector3.zero; + } + + // --------------------- + // Keyvalues + // --------------------- + //var first = WorldStorageWindow.GetFirstKeyValueTags(obj.KeyvalueTags); + //keyValuesFixed.Clear(); // no + for (int i = 0; i < keyValuesFixed.Count; i++) keyValuesFixed[i] = ("", ""); + + if (obj.KeyvalueTags.Count > 0) + { + int cnt = 0; + foreach (var item in obj.KeyvalueTags) + { + if (item.Key == "unityAuthoringPosX" || item.Key == "unityAuthoringPosY") continue; // ignore internal params + if (cnt < keyValuesFixed.Count) keyValuesFixed[cnt] = (item.Key, item.Value[0]); + cnt++; + } + } + repaint = true; + }); + } + + public override void AddObject() + { + Debug.Log("POST Trackable"); + UUID = System.Guid.Empty.ToString(); + customName = "Default Trackable"; + + Trackable obj = GenerateObject(); + TrackableRequest.CreateTrackableAsync(worldStorageServer, obj, (response) => + { + UUID = response.result; + UUID = UUID.Trim('"'); //Bugfix: remove " from server return value + WorldStorageWindow.WorldStorageWindowSingleton.GetTrackables(); + }); + } + + public override Trackable GenerateObject() + { + EncodingInformationStructure trackableEncodingInformation = new EncodingInformationStructure() + { + DataFormat = EncodingInformationStructureDataFormat.ARCORE, + Version = "1.0" + }; + Debug.Log("Created encoding information"); + + Size _trackableSize = new Size(); + + _trackableSize.Add(trackableSize.x); + _trackableSize.Add(trackableSize.y); + _trackableSize.Add(trackableSize.z); + Debug.Log("Created dimension"); + + Matrix4x4 localCRS = new Matrix4x4(); + localCRS = Matrix4x4.TRS(localCRS_pos, Quaternion.Euler(localCRS_rot), Vector3.one); + Transform3D _localCRS = WorldStorageUnityHelper.ConvertUnityToETSIARFTransform3D(localCRS); + + // Remember the position of the Unity graph node + var posX = new Collection(); + posX.Add(nodePosX.ToString()); + var posY = new Collection(); + posY.Add(nodePosY.ToString()); + + // --------------------- + // Keyvalues + // --------------------- + keyValueTags.Clear(); + keyValueTags.Add("unityAuthoringPosX", posX); + keyValueTags.Add("unityAuthoringPosY", posY); + if (keyValuesFixed.Count > 0) + foreach (var item in keyValuesFixed) + { + if (!string.IsNullOrEmpty(item.Item1)) keyValueTags.Add(item.Item1, new Collection { item.Item2 }); + } + + System.Guid _uuid = System.Guid.Parse(UUID); + System.Guid _creator = System.Guid.Parse(worldStorageUser.UUID); + Trackable t = new Trackable(customName) + { + UUID = _uuid, + CreatorUUID = _creator, + TrackableType = type, + TrackableEncodingInformation = trackableEncodingInformation, + TrackablePayload = trackablePayload, + LocalCRS = _localCRS, + Unit = unit, + Confidence = confidence, + TrackableSize = _trackableSize, + KeyvalueTags = keyValueTags + }; + return t; + } + } +} \ No newline at end of file diff --git a/Editor/Scripts/Windows/TrackableWindow.cs.meta b/Editor/Scripts/Windows/TrackableWindow.cs.meta new file mode 100644 index 0000000..020c2af --- /dev/null +++ b/Editor/Scripts/Windows/TrackableWindow.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 229d5ea484d30f945b9318581fb4f2da +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - m_ViewDataDictionary: {instanceID: 0} + - worldStorageServer: {fileID: 11400000, guid: 4f997253243de534dad12937f1284975, type: 2} + - worldStorageUser: {instanceID: 0} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/Windows/WorldAnchorWindow.cs b/Editor/Scripts/Windows/WorldAnchorWindow.cs new file mode 100644 index 0000000..649c1d0 --- /dev/null +++ b/Editor/Scripts/Windows/WorldAnchorWindow.cs @@ -0,0 +1,344 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2024 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: June 2024 +// + +#define isDEBUG + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +using UnityEngine; +using UnityEditor; +using TMPro; + +using ETSI.ARF.WorldStorage.REST; +using ETSI.ARF.OpenAPI.WorldStorage; + +namespace ETSI.ARF.WorldStorage.UI +{ + public class WorldAnchorWindow : BaseWindow + { + static public WorldAnchorWindow winSingleton; + + // World Anchors params + string UUID = System.Guid.Empty.ToString(); + string customName = "NotDefined"; + string creatorUUID = System.Guid.Empty.ToString(); + UnitSystem unit = UnitSystem.CM; + Vector3 worldAnchorSize; + Vector3 localCRS_pos; + Vector3 localCRS_rot; + + //graph params to generate the node + public bool useCoord; + public float nodePosX = 0; + public float nodePosY = 0; + + public WorldAnchorWindow() + { + // init somne stuffs + } + + public static void ShowWindow(WorldStorageServer ws, WorldStorageUser user, string UUID = "") + { + winSingleton = EditorWindow.GetWindow(typeof(WorldAnchorWindow), false, "ETSI ARF - World Anchor") as WorldAnchorWindow; + winSingleton.worldStorageServer = ws; + winSingleton.worldStorageUser = user; + if (!string.IsNullOrEmpty(UUID)) + { + winSingleton.saveText = "Update"; + winSingleton.UUID = UUID; + winSingleton.GetParams(); + } + else + { + // Create new one + winSingleton.saveText = "Create"; + winSingleton.AddObject(); + } + } + + public static GameObject GenerateAndUpdateVisual(string UUID, string name, Vector3 pos, Vector3 rot) + { + ETSI.ARF.WorldStorage.UI.Prefabs.WorldStoragePrefabs prefabs; + prefabs = (Prefabs.WorldStoragePrefabs)Resources.Load("ARFPrefabs"); + GameObject arf = GameObject.Find("ARF Visuals"); + GameObject visual = GameObject.Find(UUID); + + if (arf == null) arf = new GameObject("ARF Visuals"); + if (visual == null) + { + visual = SceneAsset.Instantiate(prefabs.worldAnchorPrefab, pos, Quaternion.Euler(rot), arf.transform); // TODO rot + visual.name = UUID; + } + else + { + visual.transform.SetPositionAndRotation(pos, Quaternion.Euler(rot)); + } + visual.transform.Find("Canvas/Text").GetComponent().text = $"Name: { name }\nUUID: { UUID }"; + return visual; + } + + void OnGUI() + { + ori = GUI.backgroundColor; // remember ori color + + gsTest = new GUIStyle("window"); + //gsTest.normal.textColor = WorldStorageWindow.arfColors[0]; + gsTest.fontStyle = FontStyle.Bold; + gsTest.alignment = TextAnchor.UpperLeft; + gsTest.fontSize = 16; + + scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.ExpandWidth(true)); + WorldStorageWindow.DrawCopyright(); + + DrawUIStuffs(); + + EditorGUILayout.EndScrollView(); + + if (GUILayout.Button("Close Window")) + { + Close(); + } + } + + public override void DrawUIStuffs() + { + GUILayout.BeginVertical(); // "World Anchor Editor", gsTest); + EditorGUILayout.Space(); + + GUILayout.BeginHorizontal(); + GUI.backgroundColor = WorldStorageWindow.arfColors[8]; + Texture anchorImage = (Texture)AssetDatabase.LoadAssetAtPath("Packages/etsi.isg.arf.worldstorage/Editor/Images/anchor.png", typeof(Texture)); + GUILayout.Box(anchorImage, GUILayout.Width(24), GUILayout.Height(24)); + GUI.backgroundColor = ori; + GUILayout.Label("World Anchor Parameters:", EditorStyles.whiteBoldLabel); + GUILayout.EndHorizontal(); + + Rect rect = EditorGUILayout.GetControlRect(false, WorldStorageWindow.lineH); + EditorGUI.DrawRect(rect, WorldStorageWindow.arfColors[8]); + + // + GUILayout.Label("Server: " + worldStorageServer.serverName, EditorStyles.whiteLargeLabel); + GUILayout.Label("User: " + worldStorageUser.userName, EditorStyles.whiteLargeLabel); + EditorGUILayout.Space(); + +#if isDEBUG + GUILayout.Label("UUID: " + UUID, EditorStyles.miniLabel); // readonly + GUILayout.Label("Creator UID: " + creatorUUID, EditorStyles.miniLabel); // readonly + EditorGUILayout.Space(); +#endif + customName = EditorGUILayout.TextField("Name of Anchor:", customName); + EditorGUILayout.Space(); + + // --------------------- + // Toolbar + // --------------------- + EditorGUILayout.BeginHorizontal(); + GUI.backgroundColor = WorldStorageWindow.arfColors[2]; + if (GUILayout.Button(saveText)) + { + Debug.Log("PUT World Anchor"); + + if (!string.IsNullOrEmpty(UUID) && UUID != "0" && UUID != System.Guid.Empty.ToString()) + { + WorldAnchor obj = GenerateObject(); + WorldAnchorRequest.UpdateWorldAnchorAsync(worldStorageServer, obj, (response) => + { + UUID = response.result; + UUID = UUID.Trim('"'); //Bugfix: remove " from server return value + + if (WorldStorageWindow.WorldStorageWindowSingleton != null) + { + WorldStorageWindow.WorldStorageWindowSingleton.GetWorldAnchors(); + } + Close(); + }); + } + } + + GUI.backgroundColor = WorldStorageWindow.arfColors[3]; + if (GUILayout.Button("Delete")) + { + if (EditorUtility.DisplayDialog("Delete", "Are you sure you want to delete this World Anchor?", "Delete", "Cancel")) + { + Debug.Log("Delete World Anchor"); + WorldAnchorRequest.DeleteWorldAnchorAsync(worldStorageServer, Guid.Parse(UUID), (response) => + { + UUID = System.Guid.Empty.ToString(); + customName = "Warning: Object deleted !"; + creatorUUID = System.Guid.Empty.ToString(); + unit = UnitSystem.CM; + if (WorldStorageWindow.WorldStorageWindowSingleton != null) + { + WorldStorageWindow.WorldStorageWindowSingleton.GetWorldAnchors(); + } + Close(); + }); + } + } + GUI.backgroundColor = ori; + + GUI.backgroundColor = WorldStorageWindow.arfColors[5]; + if (GUILayout.Button("Generate/Update GameObject")) + { + GenerateAndUpdateVisual(UUID, customName, localCRS_pos, localCRS_rot); + } + GUI.backgroundColor = ori; + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + + // --------------------- + // Params + // --------------------- + unit = (UnitSystem)EditorGUILayout.EnumPopup("Unit System:", unit); + + EditorGUILayout.Space(); + worldAnchorSize = EditorGUILayout.Vector3Field("Trackable Size:", worldAnchorSize); + + EditorGUILayout.Space(); + GUILayout.Label("Local CRS:"); + localCRS_pos = EditorGUILayout.Vector3Field(" Position:", localCRS_pos); + localCRS_rot = EditorGUILayout.Vector3Field(" Rotation:", localCRS_rot); + + // --------------------- + // Keyvalues + // --------------------- + EditorGUILayout.Space(); + groupEnabled = EditorGUILayout.BeginToggleGroup("Optional Parameters:", groupEnabled); + if (keyValuesFixed.Count > 0) + { + OutputKeyValue(0); + OutputKeyValue(1); + OutputKeyValue(2); + } + EditorGUILayout.EndToggleGroup(); + // + GUILayout.EndVertical(); + } + + public override void GetParams() + { + WorldAnchorRequest.GetWorldAnchorAsync(worldStorageServer, Guid.Parse(UUID), (response) => + { + WorldAnchor obj = response.result; + customName = obj.Name; + creatorUUID = obj.CreatorUUID.ToString(); + unit = obj.Unit; + if (obj.WorldAnchorSize.Count == 3) + { + worldAnchorSize = new Vector3((float)obj.WorldAnchorSize[0], (float)obj.WorldAnchorSize[1], (float)obj.WorldAnchorSize[2]); + } + else worldAnchorSize = Vector3.zero; + + if (obj.LocalCRS.Count == 16) + { + Matrix4x4 localCRS = WorldStorageUnityHelper.ConvertETSIARFTransform3DToUnity(obj.LocalCRS); + localCRS_pos = localCRS.GetPosition(); + localCRS_rot = localCRS.rotation.eulerAngles; + } + else + { + localCRS_pos = Vector3.zero; + localCRS_rot = Vector3.zero; + } + + // --------------------- + // Keyvalues + // --------------------- + //var first = WorldStorageWindow.GetFirstKeyValueTags(obj.KeyvalueTags); + //keyValuesFixed.Clear(); // no + for (int i = 0; i < keyValuesFixed.Count; i++) keyValuesFixed[i] = ("", ""); + + if (obj.KeyvalueTags.Count > 0) + { + int cnt = 0; + foreach (var item in obj.KeyvalueTags) + { + if (item.Key == "unityAuthoringPosX" || item.Key == "unityAuthoringPosY") continue; // ignore internal params + if (cnt < keyValuesFixed.Count) keyValuesFixed[cnt] = (item.Key, item.Value[0]); + cnt++; + } + } + repaint = true; + }); + } + + public override void AddObject() + { + Debug.Log("POST World Anchor"); + UUID = System.Guid.Empty.ToString(); + customName = "Default Anchor"; + + WorldAnchor obj = GenerateObject(); + WorldAnchorRequest.CreateWorldAnchorAsync(worldStorageServer, obj, (response) => + { + UUID = response.result; + UUID = UUID.Trim('"'); //Bugfix: remove " from server return value + WorldStorageWindow.WorldStorageWindowSingleton.GetWorldAnchors(); + }); + } + + public override WorldAnchor GenerateObject() + { + Size _worldAnchorSize = new Size(); + _worldAnchorSize.Add(worldAnchorSize.x); + _worldAnchorSize.Add(worldAnchorSize.y); + _worldAnchorSize.Add(worldAnchorSize.z); + Debug.Log("Created dimension"); + + Matrix4x4 localCRS = new Matrix4x4(); + localCRS = Matrix4x4.TRS(localCRS_pos, Quaternion.Euler(localCRS_rot), Vector3.one); + Transform3D _localCRS = WorldStorageUnityHelper.ConvertUnityToETSIARFTransform3D(localCRS); + + // Remember the position of the Unity graph node + var posX = new Collection(); + posX.Add(nodePosX.ToString()); + var posY = new Collection(); + posY.Add(nodePosY.ToString()); + + // --------------------- + // Keyvalues + // --------------------- + keyValueTags.Clear(); + keyValueTags.Add("unityAuthoringPosX", posX); + keyValueTags.Add("unityAuthoringPosY", posY); + if (keyValuesFixed.Count > 0) + foreach (var item in keyValuesFixed) + { + if (!string.IsNullOrEmpty(item.Item1)) keyValueTags.Add(item.Item1, new Collection { item.Item2 }); + } + + Guid _uuid = Guid.Parse(UUID); + Guid _creator = Guid.Parse(worldStorageUser.UUID); + WorldAnchor t = new WorldAnchor(customName) + { + UUID = _uuid, + CreatorUUID = _creator, + LocalCRS = _localCRS, + Unit = unit, + WorldAnchorSize = _worldAnchorSize, + KeyvalueTags = keyValueTags + }; + return t; + } + } +} \ No newline at end of file diff --git a/Editor/Scripts/Windows/WorldAnchorWindow.cs.meta b/Editor/Scripts/Windows/WorldAnchorWindow.cs.meta new file mode 100644 index 0000000..c4ffaff --- /dev/null +++ b/Editor/Scripts/Windows/WorldAnchorWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a0f67f823dd6ff246be6c656b120756e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/Windows/WorldGraphWindow.cs b/Editor/Scripts/Windows/WorldGraphWindow.cs new file mode 100644 index 0000000..c844cb4 --- /dev/null +++ b/Editor/Scripts/Windows/WorldGraphWindow.cs @@ -0,0 +1,304 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2024 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: July 2022 +// + +using System; +using System.Collections.Generic; + +using UnityEditor; +using UnityEditor.Experimental.GraphView; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +using ETSI.ARF.WorldStorage.Editor.Graph; +using ETSI.ARF.WorldStorage; +using ETSI.ARF.WorldStorage.REST; +using ETSI.ARF.WorldStorage.UI; +using ETSI.ARF.OpenAPI.WorldStorage; + +namespace ETSI.ARF.WorldStorage.Editor.Windows +{ + public class WorldGraphWindow : EditorWindow + { + [HideInInspector] public WorldStorageServer worldStorageServer; + [HideInInspector] public WorldStorageUser worldStorageUser; + + private ARFGraphView myGraph; + + //to delay the reframe (otherwise it reframes when the graph isn't built yet) + int twoFrames = 0; + + [MenuItem("ARFWorldStorage/Edit Graph...")] + public static void ShowWindow() + { + GetWindow("Graph Editor", true, typeof(SceneView)); + } + + public static void ShowWindowFromWorldStorageWindow(WorldStorageServer server, WorldStorageUser user) + { + var window = GetWindow("Graph Editor", true, typeof(SceneView)); + window.worldStorageServer = server; + window.worldStorageUser = user; + if (window.myGraph != null) + { + if (window.myGraph.ServerAndLocalDifferent() && EditorUtility.DisplayDialog("Saving node positions", "The World Graph has been modified. \nWould you like to push the modifications to the server ?", "Yes", "No")) + { + window.myGraph.SaveInServer(); + } + window.rootVisualElement.Remove(window.myGraph); + } + GraphEditorWindow.ResetWindow(); + SaveInfo.instance.nodePositions = null; + window.OnEnable(); + } + + public void OnEnable() + { + if (worldStorageServer != null) + { + try + { + if (SaveInfo.instance.nodePositions == null) + { + SaveInfo.instance.InitNodePos(worldStorageServer, worldStorageUser); + } + ConstructGraphView(); + myGraph.style.top = Length.Percent(11); + myGraph.style.bottom = Length.Percent(5); + rootVisualElement.Add(myGraph); + } + catch (Exception e) + { + EditorUtility.DisplayDialog("Error", "The server you selected is unreachable", "Ok"); + myGraph = null; + Debug.Log(e.ToString()); + } + } + } + + //initiate the graphView Attribute + public void ConstructGraphView() + { + myGraph = new ARFGraphView + { + name = "ARF Graph", + worldStorageServer = worldStorageServer, + worldStorageUser = worldStorageUser + }; + //top offset so that the graph does'nt overlap with the rest of the ui + myGraph.style.top = Length.Percent(11); + myGraph.PaintWorldStorage(); + myGraph.StretchToParentSize(); + SaveInfo.instance.toReFrame = true; + } + + + void OnGUI() + { + if (SaveInfo.instance.nodePositions == null) + { + SaveInfo.instance.InitNodePos(worldStorageServer, worldStorageUser); + } + + + EditorGUILayout.BeginVertical(); + + EditorGUI.BeginChangeCheck(); + worldStorageServer = (WorldStorageServer)EditorGUILayout.ObjectField("World Storage Server", worldStorageServer, typeof(WorldStorageServer), false, GUILayout.Width(500)); + worldStorageUser = (WorldStorageUser)EditorGUILayout.ObjectField("User", worldStorageUser, typeof(WorldStorageUser), false, GUILayout.Width(500)); + if (EditorGUI.EndChangeCheck()) + { + GraphEditorWindow.ResetWindow(); + + if ((myGraph != null)) + { + if (myGraph.ServerAndLocalDifferent() && EditorUtility.DisplayDialog("Saving node positions", "The World Graph has been modified. \nWould you like to push the modifications to the server ?", "Yes", "No")) + { + myGraph.SaveInServer(); + } + rootVisualElement.Remove(myGraph); + } + if (worldStorageServer != null) + { + try + { + SaveInfo.instance.InitNodePos(worldStorageServer, worldStorageUser); + ConstructGraphView(); + myGraph.style.top = Length.Percent(11); + myGraph.style.bottom = Length.Percent(5); + rootVisualElement.Add(myGraph); + Debug.Log("World Graph window initialized."); + } + catch (Exception e) + { + EditorUtility.DisplayDialog("Error", "The server you selected is unreachable", "Ok"); + myGraph = null; + Debug.Log(e.ToString()); + } + } + else + { + myGraph = null; + } + } + + + //style for copyrights label (left aligned) + var leftStyle = GUI.skin.GetStyle("Label"); + leftStyle.alignment = TextAnchor.MiddleLeft; + + GUILayout.Label("Augmented Reality Framework", leftStyle); + GUILayout.Label("Copyright (C) 2024, ETSI (BSD 3-Clause License)", leftStyle); + + //separator line + Rect rect = EditorGUILayout.GetControlRect(false, 1); + EditorGUI.DrawRect(rect, Color.gray); + + //reframe all elements to see them all + if (SaveInfo.instance.toReFrame && (twoFrames == 2)) + { + myGraph.FrameAllElements(); + SaveInfo.instance.toReFrame = false; + twoFrames = 0; + } + else if (SaveInfo.instance.toReFrame) + { + twoFrames++; + } + EditorGUILayout.EndVertical(); + + GUILayout.FlexibleSpace(); + + //Notify the user that the graph is different from the one in the server + if (myGraph != null) + { + if (myGraph.ServerAndLocalDifferent()) + { + //the icon to add if the node does not correspond to an element in the server + Texture2D warningImage = (Texture2D)AssetDatabase.LoadAssetAtPath("Packages/etsi.isg.arf.worldstorage/Editor/Images/warning.png", typeof(Texture2D)); + + GUI.backgroundColor = Color.clear; + GUILayout.BeginHorizontal(); + GUILayout.Box(warningImage, GUILayout.Width(27), GUILayout.Height(27)); + GUILayout.Box("There are elements in your graph that have been added, modified or deleted ! The current graph is not synchronized with the World Storage", leftStyle, GUILayout.ExpandWidth(true), GUILayout.Height(27)); + GUILayout.EndHorizontal(); + } + } + } + + public void DeleteNode(ARFNode node) + { + rootVisualElement.Remove(myGraph); + node.DisconnectAllPorts(myGraph); + myGraph.DeleteElements(new List { node }); + rootVisualElement.Add(myGraph); + } + + public void DeleteEdge(ARFEdgeLink edge) + { + rootVisualElement.Remove(myGraph); + myGraph.DeleteElements(new List { edge }); + rootVisualElement.Add(myGraph); + } + } + + public class SaveInfo : ScriptableSingleton + { + [SerializeField] + public Dictionary nodePositions; + public List linkIds; + + public Dictionary elemsToRemove; + public List elemsToUpdate; + + //keep the info of the graph reframe + public Boolean toReFrame = false; + + public WorldStorageServer worldStorageServer; + public WorldStorageUser worldStorageUser; + + public void InitNodePos(WorldStorageServer server, WorldStorageUser user) + { + worldStorageServer = server; + worldStorageUser = user; + + instance.nodePositions = new Dictionary(); + + List listT = TrackableRequest.GetTrackablesSync(worldStorageServer); + foreach (Trackable track in listT) + { + if (track.KeyvalueTags.ContainsKey("unityAuthoringPosX") && track.KeyvalueTags.ContainsKey("unityAuthoringPosY")) + { + var posX = RoundToNearestHalf(WorldStorageRequest.FloatParse(track.KeyvalueTags["unityAuthoringPosX"][0])); + var posY = RoundToNearestHalf(WorldStorageRequest.FloatParse(track.KeyvalueTags["unityAuthoringPosY"][0])); + Rect trackPos = new(posX, posY, 135, 77); + instance.nodePositions[track.UUID.ToString()] = trackPos; + } + else + { + Rect trackPos = new(0, 0, 135, 77); + instance.nodePositions[track.UUID.ToString()] = trackPos; + } + } + + List listA = WorldAnchorRequest.GetWorldAnchorsSync(worldStorageServer); + Debug.Log("Anchors " +listA.Count); + foreach (WorldAnchor wa in listA) + { + if (wa.KeyvalueTags.ContainsKey("unityAuthoringPosX") && wa.KeyvalueTags.ContainsKey("unityAuthoringPosY")) + { + var posX = RoundToNearestHalf(WorldStorageRequest.FloatParse(wa.KeyvalueTags["unityAuthoringPosX"][0])); + var posY = RoundToNearestHalf(WorldStorageRequest.FloatParse(wa.KeyvalueTags["unityAuthoringPosY"][0])); + Rect waPos = new(posX, posY, 135, 77); + instance.nodePositions[wa.UUID.ToString()] = waPos; + } + else + { + Rect trackPos = new(0, 0, 135, 77); + instance.nodePositions[wa.UUID.ToString()] = trackPos; + } + } + + + instance.linkIds = new List(); + List listWL = WorldLinkRequest.GetWorldLinksSync(worldStorageServer); + foreach (WorldLink link in listWL) + { + instance.linkIds.Add(link.UUID.ToString()); + } + + instance.elemsToRemove = new Dictionary(); + instance.elemsToUpdate = new List(); + } + + //method to predict the position of a node (the float that will be saved in the PositionInfo singleton) + public static float RoundToNearestHalf(float a) + { + return a = Mathf.Round(a * 2f) * 0.5f; + } + + public static void PrintInfo() + { + Debug.Log("elems to delete : " + string.Join(", ", instance.elemsToRemove.Keys)); + Debug.Log("elems to update : " + string.Join(", ", instance.elemsToUpdate)); + Debug.Log("elems tout court : " + string.Join(", ", instance.nodePositions.Keys)); + } + } +} \ No newline at end of file diff --git a/Editor/Scripts/Windows/WorldGraphWindow.cs.meta b/Editor/Scripts/Windows/WorldGraphWindow.cs.meta new file mode 100644 index 0000000..add6292 --- /dev/null +++ b/Editor/Scripts/Windows/WorldGraphWindow.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 2c1a0c92306453d46897c1af6cb5c2f9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - m_ViewDataDictionary: {instanceID: 0} + - worldStorageServer: {instanceID: 0} + - worldStorageUser: {fileID: 11400000, guid: c0696089e4a855b46ad490437919b1e8, type: 2} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/Windows/WorldLinkWindow.cs b/Editor/Scripts/Windows/WorldLinkWindow.cs new file mode 100644 index 0000000..147417b --- /dev/null +++ b/Editor/Scripts/Windows/WorldLinkWindow.cs @@ -0,0 +1,515 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2024 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: June 2024 +// + +#define isDEBUG + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +using UnityEngine; +using UnityEditor; +using TMPro; + +using ETSI.ARF.WorldStorage.REST; +using ETSI.ARF.OpenAPI.WorldStorage; + +namespace ETSI.ARF.WorldStorage.UI +{ + public class WorldLinkWindow : BaseWindow + { + static public WorldLinkWindow winSingleton; + + public class Element + { + public string UUID = System.Guid.Empty.ToString(); + public string name = "(none)"; + public TypeWorldStorage type = TypeWorldStorage.UNKNOWN; + public Vector3 pos = Vector3.zero; + } + + [SerializeField] public List anchors = new List(); + + private static GUILayoutOption miniButtonWidth = GUILayout.Width(50); + + // World Anchors params + string UUID = System.Guid.Empty.ToString(); + string customName = "(no name for World Links)"; + string creatorUUID = System.Guid.Empty.ToString(); + + // From & To elements: + private bool showListFrom = true; + private bool showListTo = true; + private Element FROM = new Element(); + private Element TO = new Element(); + + UnitSystem unit = UnitSystem.CM; + Vector3 transf_pos; + Vector3 transf_rot; + + public WorldLinkWindow() + { + // init somne stuffs + } + + public static void ShowWindow(WorldStorageServer ws, WorldStorageUser user, string UUID = "") + { + winSingleton = EditorWindow.GetWindow(typeof(WorldLinkWindow), false, "ETSI ARF - World Link") as WorldLinkWindow; + winSingleton.worldStorageServer = ws; + winSingleton.worldStorageUser = user; + if (!string.IsNullOrEmpty(UUID)) + { + winSingleton.saveText = "Update"; + winSingleton.UUID = UUID; + winSingleton.GetParams(); + } + else + { + // Create new one + winSingleton.saveText = "Create"; + winSingleton.AddObject(); + } + } + + public static GameObject GenerateAndUpdateVisual(string UUID, Element from, Element to) + { + ETSI.ARF.WorldStorage.UI.Prefabs.WorldStoragePrefabs prefabs; + prefabs = (Prefabs.WorldStoragePrefabs)Resources.Load("ARFPrefabs"); + GameObject arf = GameObject.Find("ARF Visuals"); + GameObject visual = GameObject.Find(UUID); + + //Value between from and to + Vector3 centerPos = (from.pos + to.pos) * 0.5f; + Vector3 rot = Vector3.zero; // Direction + + if (arf == null) arf = new GameObject("ARF Visuals"); + if (visual == null) + { + visual = SceneAsset.Instantiate(prefabs.worldLinkPrefab, centerPos, Quaternion.Euler(rot), arf.transform); // TODO rot + visual.name = UUID; + } + else + { + visual.transform.SetPositionAndRotation(centerPos, Quaternion.Euler(rot)); + } + + // Update the gizno, if GaneObject are founds!!! + GameObject go1 = GameObject.Find(from.UUID); + GameObject go2 = GameObject.Find(to.UUID); + if (go1 && go2) + { + LinkVisual gizmo = visual.GetComponent(); + if (gizmo) + { + gizmo.fromElement = go1; + gizmo.toElement = go2; + } + } + + // Update the annotation + visual.transform.Find("Canvas/Text").GetComponent().text = $"UUID: { UUID }\nFrom: { from.name }\nTo: { to.name }"; + return visual; + } + + + void OnGUI() + { + ori = GUI.backgroundColor; // remember ori color + + gsTest = new GUIStyle("window"); + //gsTest.normal.textColor = WorldStorageWindow.arfColors[0]; + gsTest.fontStyle = FontStyle.Bold; + gsTest.alignment = TextAnchor.UpperLeft; + gsTest.fontSize = 16; + gsTest.fixedHeight = 100; + + scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.ExpandWidth(true)); + WorldStorageWindow.DrawCopyright(); + + DrawUIStuffs(); + + EditorGUILayout.EndScrollView(); + + if (GUILayout.Button("Close Window")) + { + Close(); + } + } + + private void GetElementFROM() + { + // Trackable? + TrackableRequest.GetTrackableAsync(worldStorageServer, Guid.Parse(FROM.UUID), (response) => + { + try + { + Trackable result = response.result; + FROM.name = result.Name; + FROM.type = TypeWorldStorage.TRACKABLE; + + Matrix4x4 localCRS = WorldStorageUnityHelper.ConvertETSIARFTransform3DToUnity(result.LocalCRS); + FROM.pos = localCRS.GetPosition(); + } + catch + { + // Anchor? + WorldAnchorRequest.GetWorldAnchorAsync(worldStorageServer, Guid.Parse(FROM.UUID), (response) => + { + try + { + WorldAnchor result = response.result; + FROM.name = result.Name; + FROM.type = TypeWorldStorage.ANCHOR; + + Matrix4x4 localCRS = WorldStorageUnityHelper.ConvertETSIARFTransform3DToUnity(result.LocalCRS); + FROM.pos = localCRS.GetPosition(); + } + catch + { + // Nothing! + FROM.name = ""; + FROM.type = TypeWorldStorage.UNKNOWN; + } + }); + } + }); + } + + private void GetElementTO() + { + // Trackable? + TrackableRequest.GetTrackableAsync(worldStorageServer, Guid.Parse(TO.UUID), (response) => + { + try + { + Trackable result = response.result; + TO.name = result.Name; + TO.type = TypeWorldStorage.TRACKABLE; + + Matrix4x4 localCRS = WorldStorageUnityHelper.ConvertETSIARFTransform3DToUnity(result.LocalCRS); + TO.pos = localCRS.GetPosition(); + } + catch + { + // Anchor? + WorldAnchorRequest.GetWorldAnchorAsync(worldStorageServer, Guid.Parse(TO.UUID), (response) => + { + try + { + WorldAnchor result = response.result; + TO.name = result.Name; + TO.type = TypeWorldStorage.ANCHOR; + + Matrix4x4 localCRS = WorldStorageUnityHelper.ConvertETSIARFTransform3DToUnity(result.LocalCRS); + TO.pos = localCRS.GetPosition(); + } + catch + { + // Nothing! + TO.UUID = System.Guid.Empty.ToString(); + TO.name = ""; + TO.type = TypeWorldStorage.UNKNOWN; + } + }); + } + }); + } + + public override void DrawUIStuffs() + { + GUILayout.BeginVertical(); // "World Link Editor", gsTest); + EditorGUILayout.Space(); + + GUILayout.BeginHorizontal(); + GUI.backgroundColor = WorldStorageWindow.arfColors[9]; + Texture linkImage = (Texture)AssetDatabase.LoadAssetAtPath("Packages/etsi.isg.arf.worldstorage/Editor/Images/link.png", typeof(Texture)); + GUILayout.Box(linkImage, GUILayout.Width(24), GUILayout.Height(24)); + GUI.backgroundColor = ori; + GUILayout.Label("World Link Parameters:", EditorStyles.whiteBoldLabel); + GUILayout.EndHorizontal(); + + Rect rect = EditorGUILayout.GetControlRect(false, WorldStorageWindow.lineH); + EditorGUI.DrawRect(rect, WorldStorageWindow.arfColors[9]); + + // + GUILayout.Label("Server: " + worldStorageServer.serverName, EditorStyles.whiteLargeLabel); + GUILayout.Label("User: " + worldStorageUser.userName, EditorStyles.whiteLargeLabel); + EditorGUILayout.Space(); + +#if isDEBUG + GUILayout.Label("UUID: " + UUID, EditorStyles.miniLabel); // readonly + GUILayout.Label("Creator UID: " + creatorUUID, EditorStyles.miniLabel); // readonly +#endif + + EditorGUILayout.Space(); + + // --------------------- + // Toolbar + // --------------------- + EditorGUILayout.BeginHorizontal(); + GUI.backgroundColor = WorldStorageWindow.arfColors[2]; + if (GUILayout.Button(saveText)) + { + Debug.Log("PUT World Link"); + + if (!string.IsNullOrEmpty(UUID) && UUID != "0" && UUID != System.Guid.Empty.ToString()) + { + WorldLink obj = GenerateObject(); + WorldLinkRequest.UpdateWorldLinkAsync(worldStorageServer, obj, (response) => + { + UUID = response.result; + UUID = UUID.Trim('"'); //Bugfix: remove " from server return value + + if (WorldStorageWindow.WorldStorageWindowSingleton != null) + { + WorldStorageWindow.WorldStorageWindowSingleton.GetWorldLinks(); + } + Close(); + }); + } + } + + GUI.backgroundColor = WorldStorageWindow.arfColors[3]; + if (GUILayout.Button("Delete")) + { + if (EditorUtility.DisplayDialog("Delete", "Are you sure you want to delete this World Link?", "Delete", "Cancel")) + { + Debug.Log("Delete World Link"); + WorldLinkRequest.DeleteWorldLinkAsync(worldStorageServer, Guid.Parse(UUID), (response) => + { + UUID = System.Guid.Empty.ToString(); + customName = "Warning: Object deleted !"; + creatorUUID = System.Guid.Empty.ToString(); + unit = UnitSystem.CM; + WorldStorageWindow.WorldStorageWindowSingleton.GetWorldLinks(); + }); + } + } + GUI.backgroundColor = ori; + + GUI.backgroundColor = WorldStorageWindow.arfColors[5]; + if (GUILayout.Button("Generate/Update GameObject")) + { + GenerateAndUpdateVisual(UUID, FROM, TO); + } + GUI.backgroundColor = ori; + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + + // --------------------- + // Params + // --------------------- + string lastFromUUID = FROM.UUID; + string lastToUUID = TO.UUID; + + if (GUILayout.Button("Use 'From-To' Objects from Scene Selection")) + { + GameObject from, to; + GameObject[] SelectedObjects = Selection.gameObjects; + + if (SelectedObjects.Length == 2) + { + Debug.Log("Creation du lien (Many thanks Eric ;-)"); + from = SelectedObjects[0]; + to = SelectedObjects[1]; + FROM.UUID = from.name; + TO.UUID = to.name; + } + else + { + EditorUtility.DisplayDialog("Selection", "Please select exactly 2 GameObject from typ Trackable(s) and/or WorldAnchor(s) in the scene!", "OK"); + } + } + + showListFrom = EditorGUILayout.Foldout(showListFrom, "Parent Object (From)"); + if (showListFrom) + { + EditorGUILayout.BeginHorizontal(); + FROM.UUID = EditorGUILayout.TextField("UUID:", FROM.UUID); + if (FROM.UUID.Contains("[")) + { + // extract the UUID + FROM.UUID = FROM.UUID.Split('[', ']')[1]; + } + + GUI.backgroundColor = WorldStorageWindow.arfColors[0]; + if (GUILayout.Button("Request", EditorStyles.miniButtonLeft, miniButtonWidth) || lastFromUUID != FROM.UUID) + { + GetElementFROM(); + } + EditorGUILayout.EndHorizontal(); + GUI.backgroundColor = ori; + EditorGUILayout.LabelField("Name:", FROM.name); + EditorGUILayout.LabelField("Type:", FROM.type.ToString()); + } + + EditorGUILayout.Space(); + showListTo = EditorGUILayout.Foldout(showListTo, "Child Object (To)"); + if (showListTo) + { + EditorGUILayout.BeginHorizontal(); + TO.UUID = EditorGUILayout.TextField("UUID:", TO.UUID); + if (TO.UUID.Contains("[")) + { + // extract the UUID + TO.UUID = TO.UUID.Split('[', ']')[1]; + } + GUI.backgroundColor = WorldStorageWindow.arfColors[0]; + if (GUILayout.Button("Request", EditorStyles.miniButtonLeft, miniButtonWidth) || lastToUUID != TO.UUID) + { + GetElementTO(); + } + EditorGUILayout.EndHorizontal(); + GUI.backgroundColor = ori; + EditorGUILayout.LabelField("Name:", TO.name); + EditorGUILayout.LabelField("Type:", TO.type.ToString()); + } + + EditorGUILayout.Space(); + unit = (UnitSystem)EditorGUILayout.EnumPopup("Unit System:", unit); + + EditorGUILayout.Space(); + //TODO Is this required??? + GUILayout.Label("Transform:"); + transf_pos = EditorGUILayout.Vector3Field("Position:", transf_pos); + transf_rot = EditorGUILayout.Vector3Field("Rotation:", transf_rot); + + // --------------------- + // Keyvalues + // --------------------- + EditorGUILayout.Space(); + groupEnabled = EditorGUILayout.BeginToggleGroup("Optional Parameters:", groupEnabled); + if (keyValuesFixed.Count > 0) + { + OutputKeyValue(0); + OutputKeyValue(1); + OutputKeyValue(2); + } + EditorGUILayout.EndToggleGroup(); + // + GUILayout.EndVertical(); + } + + public override void GetParams() + { + WorldLinkRequest.GetWorldLinkAsync(worldStorageServer, Guid.Parse(UUID), (response) => + { + WorldLink obj = response.result; + //customName = obj.Name; + creatorUUID = obj.CreatorUUID.ToString(); + + FROM.UUID = obj.UUIDFrom.ToString(); + FROM.type = obj.TypeFrom; + + TO.UUID = obj.UUIDTo.ToString(); + TO.type = obj.TypeTo; + + unit = obj.Unit; + if (obj.Transform.Count == 16) + { + Matrix4x4 transf = WorldStorageUnityHelper.ConvertETSIARFTransform3DToUnity(obj.Transform); + transf_pos = transf.GetPosition(); + transf_rot = transf.rotation.eulerAngles; + } + else + { + transf_pos = Vector3.zero; + transf_rot = Vector3.zero; + } + + // Get here the params of the from/to elements (GET) + GetElementFROM(); + GetElementTO(); + + // --------------------- + // Keyvalues + // --------------------- + //var first = WorldStorageWindow.GetFirstKeyValueTags(obj.KeyvalueTags); + //keyValuesFixed.Clear(); // no + for (int i = 0; i < keyValuesFixed.Count; i++) keyValuesFixed[i] = ("", ""); + + if (obj.KeyvalueTags.Count > 0) + { + int cnt = 0; + foreach (var item in obj.KeyvalueTags) + { + if (item.Key == "unityAuthoringPosX" || item.Key == "unityAuthoringPosY") continue; // ignore internal params + if (cnt < keyValuesFixed.Count) keyValuesFixed[cnt] = (item.Key, item.Value[0]); + cnt++; + } + } + repaint = true; + }); + } + + public override void AddObject() + { + Debug.Log("POST World Link"); + UUID = System.Guid.Empty.ToString(); + customName = "Default Link"; + + WorldLink obj = GenerateObject(); + WorldLinkRequest.CreateWorldLinkAsync(worldStorageServer, obj, (response) => + { + UUID = response.result; + UUID = UUID.Trim('"'); //Bugfix: remove " from server return value + WorldStorageWindow.WorldStorageWindowSingleton.GetWorldLinks(); + }); + } + + public override WorldLink GenerateObject() + { + Matrix4x4 localCRS = new Matrix4x4(); + localCRS = Matrix4x4.TRS(transf_pos, Quaternion.Euler(transf_rot), Vector3.one); + Transform3D transform3d = WorldStorageUnityHelper.ConvertUnityToETSIARFTransform3D(localCRS); + + // --------------------- + // Keyvalues + // --------------------- + keyValueTags.Clear(); + //keyValueTags.Add("unityAuthoringPosX", posX); + //keyValueTags.Add("unityAuthoringPosY", posY); + if (keyValuesFixed.Count > 0) + foreach (var item in keyValuesFixed) + { + if (!string.IsNullOrEmpty(item.Item1)) keyValueTags.Add(item.Item1, new Collection { item.Item2 }); + } + + System.Guid _uuid = System.Guid.Parse(UUID); + System.Guid _creator = System.Guid.Parse(worldStorageUser.UUID); + System.Guid _from = System.Guid.Parse(FROM.UUID); + System.Guid _to = System.Guid.Parse(TO.UUID); + WorldLink t = new WorldLink() + { + UUID = _uuid, + CreatorUUID = _creator, + UUIDFrom = _from, + UUIDTo = _to, + TypeFrom = FROM.type, + TypeTo = TO.type, + Transform = transform3d, + Unit = unit, + KeyvalueTags = keyValueTags + }; + return t; + } + } +} \ No newline at end of file diff --git a/Editor/Scripts/Windows/WorldLinkWindow.cs.meta b/Editor/Scripts/Windows/WorldLinkWindow.cs.meta new file mode 100644 index 0000000..6fdeb44 --- /dev/null +++ b/Editor/Scripts/Windows/WorldLinkWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f66d40f8781c5784cbe1013328d78ae6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/Windows/WorldStorageWindow.cs b/Editor/Scripts/Windows/WorldStorageWindow.cs new file mode 100644 index 0000000..14d08cd --- /dev/null +++ b/Editor/Scripts/Windows/WorldStorageWindow.cs @@ -0,0 +1,642 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2024 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: June 2024 +// + +#define isDEBUG + +using System; +using System.Collections; +using System.Collections.Generic; + +using UnityEngine; +using UnityEditor; + +using ETSI.ARF.WorldStorage; +using ETSI.ARF.WorldStorage.REST; +using ETSI.ARF.WorldStorage.Editor.Windows; +using ETSI.ARF.OpenAPI.WorldStorage; + +namespace ETSI.ARF.WorldStorage.UI +{ + public class WorldStorageWindow : EditorWindow + { + static public WorldStorageWindow WorldStorageWindowSingleton; + static public string lastUserID = "8fb169e2-8910-4cd5-a8f9-b7abff38d013"; // dummy + + [HideInInspector] public WorldStorageServer worldStorageServer; + [HideInInspector] public WorldStorageUser worldStorageUser; + + [SerializeField] public List creators = new List(); + [SerializeField] public List trackables = new List(); + [SerializeField] public List anchors = new List(); + [SerializeField] public List links = new List(); + + string ping = "-"; + string state = "Unknow"; + string vers = "Unknow"; + + private bool repaint = false; + private Vector2 scrollPos; + private Color ori; + private GUIStyle gsTest; + + private static GUILayoutOption miniButtonWidth = GUILayout.Width(32); + private static GUILayoutOption buttonWidth = GUILayout.Width(64f); + private bool showListT = true; + private bool showListA = true; + private bool showListL = true; + + private string filterByKeyValueTag = ""; + + static public string winName = "ARF Authoring Editor"; + static public int lineH = 5; + static public Color[] arfColors = new Color[] + { + Color.yellow, // paneltext + new Color(0.3f, 1f, 1f), // button REST + new Color(0.3f, 1f, 0.3f), // button create + new Color(1f, 0f, 0f), // button delete (red) + new Color(.5f, .7f, 1f), // button graph window + new Color(.3f, .7f, 1f), // button generate prefab + new Color(1f, 1f, 0.3f), // button request + new Color(1f, 0.3f, 0.3f), // 7/ color for trackables + new Color(1f, 0.7f, 0f), // 8/ color for anchors + new Color(.66f, .4f, 1f), // 9/ color for links + new Color(.66f, .66f, 66f), // color for light grey + new Color(.22f, .22f, 22f) // color for dark grey + }; + + + //[MenuItem("[ ISG-ARF ]/World Storage Editor")] + public static void ShowWindow() + { + WorldStorageWindowSingleton = EditorWindow.GetWindow(typeof(WorldStorageWindow), false, WorldStorageWindow.winName) as WorldStorageWindow; + OpenAPI.ResponseObject ro = AdminRequest.PingAsync(WorldStorageWindowSingleton.worldStorageServer, (response) => + { + WorldStorageWindowSingleton.ping = response.result; + WorldStorageWindowSingleton.repaint = true; + }); + WorldStorageWindow.lastUserID = WorldStorageWindowSingleton.worldStorageUser.UUID; + } + + public void Update() + { + if (repaint) + { + Repaint(); + repaint = false; + } + } + + public WorldStorageWindow() + { + } + + static public void DrawCopyright() + { + // Title + GUILayout.Label("Augmented Reality Framework", EditorStyles.boldLabel); + GUILayout.Label("Copyright (C) 2024, ETSI (BSD 3-Clause License)"); + } + + void OnGUI() + { + ori = GUI.backgroundColor; + gsTest = new GUIStyle("window"); + //gsTest.normal.textColor = WorldStorageWindow.arfColors[0]; + gsTest.fontStyle = FontStyle.Bold; + gsTest.alignment = TextAnchor.UpperLeft; + gsTest.fontSize = 16; + + scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.ExpandWidth(true)); + WorldStorageWindow.DrawCopyright(); + + // Server info + GUILayout.BeginVertical("World Storage Server", gsTest); + EditorGUILayout.Space(); + Rect rect = EditorGUILayout.GetControlRect(false, 1); // WorldStorageWindow.lineH); + EditorGUI.DrawRect(rect, Color.black); + // + GUILayout gl = new GUILayout(); + + GUILayout.Label("Server Name: " + worldStorageServer.serverName, EditorStyles.whiteLargeLabel); + GUILayout.Label("User Name: " + worldStorageUser.userName, EditorStyles.whiteLargeLabel); +#if isDEBUG + GUILayout.Label("Creator UID: " + worldStorageUser.UUID); + GUILayout.Label("Base Path: " + worldStorageServer.basePath); + GUILayout.Label("Port: " + worldStorageServer.port); +#endif + + GUI.backgroundColor = WorldStorageWindow.arfColors[1]; + if (GUILayout.Button("Open World Representation Graph Window...")) + { + WorldGraphWindow.ShowWindowFromWorldStorageWindow(worldStorageServer, worldStorageUser); + } + GUI.backgroundColor = ori; + + DrawElementStuffs(); + + EditorGUILayout.EndScrollView(); + } + + public void OnInspectorUpdate() + { + this.Repaint(); + } + + void DrawElementStuffs() + { + + EditorGUILayout.Space(); + + // ########################################################### + // Handle admin + // ########################################################### + #region Ping + GUILayout.BeginHorizontal(); + ping = EditorGUILayout.TextField("Last Ping", ping); + if (GUILayout.Button("Ping")) + { + OpenAPI.ResponseObject ro = AdminRequest.PingAsync(worldStorageServer, (response) => + { + ping = response.result; + }); + } + GUI.backgroundColor = ori; + GUILayout.EndHorizontal(); + #endregion + + #region State + GUILayout.BeginHorizontal(); + state = EditorGUILayout.TextField("State", state); + + if (GUILayout.Button("Get World Storage Sate")) + { + OpenAPI.ResponseObject ro = AdminRequest.AdminAsync(worldStorageServer, (response) => + { + state = response.result; + }); + } + GUI.backgroundColor = ori; + GUILayout.EndHorizontal(); + #endregion + + #region Version + GUILayout.BeginHorizontal(); + vers = EditorGUILayout.TextField("Version", vers); + + if (GUILayout.Button("Get World Storage API Version")) + { + OpenAPI.ResponseObject ro = AdminRequest.VersionAsync(worldStorageServer, (response) => + { + vers = response.result; + }); + } + GUI.backgroundColor = ori; + GUILayout.EndHorizontal(); + #endregion + + EditorGUILayout.Space(); + + ScriptableObject target = this; + SerializedObject so = new SerializedObject(target); + + // ########################################################### + // Get creators + // ########################################################### + #region Get all creator UUID + EditorGUILayout.Space(); + GUI.backgroundColor = WorldStorageWindow.arfColors[4]; + if (GUILayout.Button("Request UUID of Creators")) GetCreators(); + GUI.backgroundColor = ori; + + SerializedProperty stringsProperty = so.FindProperty("creators"); + EditorGUILayout.PropertyField(stringsProperty, true); // True means show children + so.ApplyModifiedProperties(); // Remember to apply modified properties + #endregion + + //EditorGUILayout.Space(); + //GUILayout.Label("World Storage Elements:", EditorStyles.whiteLargeLabel); + + + // ########################################################### + // Filter (Key = Group) + // ########################################################### + #region Filter + EditorGUILayout.Space(); + filterByKeyValueTag = EditorGUILayout.TextField("Filter for KeyValue Group:", filterByKeyValueTag); + #endregion + + // ########################################################### + // Handle trackables + // ########################################################### + #region Get all trackable objects + EditorGUILayout.Space(); + + GUI.backgroundColor = WorldStorageWindow.arfColors[0]; + if (GUILayout.Button("Request All")) + { + GetTrackables(); + GetWorldAnchors(); + GetWorldLinks(); + } + + + GUILayout.BeginHorizontal(); + GUI.backgroundColor = WorldStorageWindow.arfColors[7]; + Texture trackableImage = (Texture)AssetDatabase.LoadAssetAtPath("Packages/etsi.isg.arf.worldstorage/Editor/Images/trackable.png", typeof(Texture)); + GUILayout.Box(trackableImage, GUILayout.Width(24), GUILayout.Height(24)); + GUI.backgroundColor = ori; + GUILayout.Label("Trackables:", EditorStyles.whiteBoldLabel); + GUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + GUI.backgroundColor = WorldStorageWindow.arfColors[0]; + if (GUILayout.Button("Request Trackables")) + { + GetTrackables(); + } + + GUI.backgroundColor = WorldStorageWindow.arfColors[2]; + if (GUILayout.Button("Create New")) + { + Debug.Log("Create trackable and open window"); + TrackableWindow.ShowWindow(worldStorageServer, worldStorageUser); + } + + GUI.backgroundColor = ori; + //GUI.backgroundColor = WorldStorageWindow.arfColors[3]; + if (GUILayout.Button("Delete all Trackables (3 stay in!!!)")) + { + if (EditorUtility.DisplayDialog("Deleting elements", "Do you really want to delete all trackables?", "Yes", "No")) + { + Debug.Log("Deleting all Trackable "); + int n = 0; + string UUID; + foreach (var customName in trackables) + { + if (!customName.Contains("[")) UUID = customName; + else + { + // extract the UUID + UUID = customName.Split('[', ']')[1]; + } + if (++n > 3) TrackableRequest.DeleteTrackableAsync(worldStorageServer, Guid.Parse(UUID), (response) => + { + // nothing to do + }); + } + + GetTrackables(); + WorldStorageWindow.WorldStorageWindowSingleton.repaint = true; + } + } + GUI.backgroundColor = ori; + EditorGUILayout.EndHorizontal(); + + // Show list + stringsProperty = so.FindProperty("trackables"); + showListT = EditorGUILayout.BeginFoldoutHeaderGroup(showListT, "List of Trackables"); + if (showListT) + for (int i = 0; i < stringsProperty.arraySize; i++) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PropertyField(stringsProperty.GetArrayElementAtIndex(i)); + + string UUID = WorldStorageWindow.GetUUIDFromString(stringsProperty.GetArrayElementAtIndex(i).stringValue); + if (UUID == null && i < trackables.Count) UUID = trackables[i]; // try this + if (GUILayout.Button("Edit...", EditorStyles.miniButtonLeft, buttonWidth)) + { + Debug.Log("Open Trackable Window"); + TrackableWindow.ShowWindow(worldStorageServer, worldStorageUser, UUID); + } + + GUI.backgroundColor = WorldStorageWindow.arfColors[3]; + if (GUILayout.Button("X", EditorStyles.miniButtonLeft, miniButtonWidth)) + { + if (EditorUtility.DisplayDialog("Delete", "Are you sure you want to delete this element?", "Delete", "Cancel")) + { + TrackableRequest.DeleteTrackableAsync(worldStorageServer, Guid.Parse(UUID), (response) => + { + WorldStorageWindowSingleton.GetTrackables(); + WorldStorageWindowSingleton.repaint = true; + }); + } + } + GUI.backgroundColor = ori; + + EditorGUILayout.EndHorizontal(); + } + EditorGUILayout.EndFoldoutHeaderGroup(); + #endregion + + // ########################################################### + // Handle anchors + // ########################################################### + #region Get all anchor objects + EditorGUILayout.Space(); + + GUILayout.BeginHorizontal(); + GUI.backgroundColor = WorldStorageWindow.arfColors[8]; + Texture anchorImage = (Texture)AssetDatabase.LoadAssetAtPath("Packages/etsi.isg.arf.worldstorage/Editor/Images/anchor.png", typeof(Texture)); + GUILayout.Box(anchorImage, GUILayout.Width(24), GUILayout.Height(24)); + GUI.backgroundColor = ori; + GUILayout.Label("World Anchors:", EditorStyles.whiteBoldLabel); + GUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + GUI.backgroundColor = WorldStorageWindow.arfColors[0]; + if (GUILayout.Button("Request Anchors")) + { + GetWorldAnchors(); + } + + GUI.backgroundColor = WorldStorageWindow.arfColors[2]; + if (GUILayout.Button("Create New")) + { + Debug.Log("Create anchor and open window"); + WorldAnchorWindow.ShowWindow(worldStorageServer, worldStorageUser); + } + + GUI.backgroundColor = ori; + //GUI.backgroundColor = WorldStorageWindow.arfColors[3]; + if (GUILayout.Button("Delete all Anchors (3 stay in!!!)")) + { + if (EditorUtility.DisplayDialog("Deleting elements", "Do you really want to delete all anchors?", "Yes", "No")) + { + Debug.Log("Deleting all World Anchors "); + int n = 0; + string UUID; + foreach (var customName in anchors) + { + if (!customName.Contains("[")) UUID = customName; + else + { + // extract the UUID + UUID = customName.Split('[', ']')[1]; + } + if (++n > 3) WorldAnchorRequest.DeleteWorldAnchorAsync(worldStorageServer, Guid.Parse(UUID), (response) => + { + WorldStorageWindowSingleton.GetWorldAnchors(); + WorldStorageWindowSingleton.repaint = true; + }); + } + } + } + GUI.backgroundColor = ori; + EditorGUILayout.EndHorizontal(); + + // Show list + stringsProperty = so.FindProperty("anchors"); + showListA = EditorGUILayout.BeginFoldoutHeaderGroup(showListA, "List of World Anchors"); + if (showListA) + for (int i = 0; i < stringsProperty.arraySize; i++) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PropertyField(stringsProperty.GetArrayElementAtIndex(i)); + + string UUID = WorldStorageWindow.GetUUIDFromString(stringsProperty.GetArrayElementAtIndex(i).stringValue); + if (UUID == null && i < anchors.Count) UUID = anchors[i]; // try this + if (GUILayout.Button("Edit...", EditorStyles.miniButtonLeft, buttonWidth)) + { + Debug.Log("Open Anchor Window"); + WorldAnchorWindow.ShowWindow(worldStorageServer, worldStorageUser, UUID); + } + + GUI.backgroundColor = WorldStorageWindow.arfColors[3]; + if (GUILayout.Button("X", EditorStyles.miniButtonLeft, miniButtonWidth)) + { + if (EditorUtility.DisplayDialog("Delete", "Are you sure you want to delete this element?", "Delete", "Cancel")) + { + WorldAnchorRequest.DeleteWorldAnchorAsync(worldStorageServer, Guid.Parse(UUID), (response) => + { + WorldStorageWindowSingleton.GetWorldAnchors(); + }); + } + } + GUI.backgroundColor = ori; + + EditorGUILayout.EndHorizontal(); + } + EditorGUILayout.EndFoldoutHeaderGroup(); + #endregion + + // ########################################################### + // Handle Links + // ########################################################### + #region Get all link objects + EditorGUILayout.Space(); + + GUILayout.BeginHorizontal(); + GUI.backgroundColor = WorldStorageWindow.arfColors[9]; + Texture linkImage = (Texture)AssetDatabase.LoadAssetAtPath("Packages/etsi.isg.arf.worldstorage/Editor/Images/link.png", typeof(Texture)); + GUILayout.Box(linkImage, GUILayout.Width(24), GUILayout.Height(24)); + GUI.backgroundColor = ori; + GUILayout.Label("World Links:", EditorStyles.whiteBoldLabel); + GUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + GUI.backgroundColor = WorldStorageWindow.arfColors[0]; + if (GUILayout.Button("Request Links")) + { + GetWorldLinks(); + } + + GUI.backgroundColor = WorldStorageWindow.arfColors[2]; + if (GUILayout.Button("Create New")) + { + Debug.Log("Create link and open window"); + WorldLinkWindow.ShowWindow(worldStorageServer, worldStorageUser); + } + + GUI.backgroundColor = ori; + //GUI.backgroundColor = WorldStorageWindow.arfColors[3]; + if (GUILayout.Button("Delete all Links (3 stay in!!!)")) + { + if (EditorUtility.DisplayDialog("Deleting elements", "Do you really want to delete all links?", "Yes", "No")) + { + Debug.Log("Deleting all World Links"); + int n = 0; + string UUID; + foreach (var customName in links) + { + if (!customName.Contains("[")) UUID = customName; + else + { + // extract the UUID + UUID = customName.Split('[', ']')[1]; + } + if (++n > 3) WorldLinkRequest.DeleteWorldLinkAsync(worldStorageServer, Guid.Parse(UUID), (response) => + { + WorldStorageWindowSingleton.GetWorldLinks(); + }); + } + } + } + GUI.backgroundColor = ori; + EditorGUILayout.EndHorizontal(); + + // Show list + stringsProperty = so.FindProperty("links"); + showListL = EditorGUILayout.BeginFoldoutHeaderGroup(showListL, "List of World Links"); + if (showListL) + for (int i = 0; i < stringsProperty.arraySize; i++) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PropertyField(stringsProperty.GetArrayElementAtIndex(i)); + + string UUID = WorldStorageWindow.GetUUIDFromString(stringsProperty.GetArrayElementAtIndex(i).stringValue); + if (UUID == null && i < links.Count) UUID = links[i]; // try this + if (GUILayout.Button("Edit...", EditorStyles.miniButtonLeft, buttonWidth)) + { + Debug.Log("Open Link Window"); + + WorldLinkWindow.ShowWindow(worldStorageServer, worldStorageUser, UUID); + } + + GUI.backgroundColor = WorldStorageWindow.arfColors[3]; + if (GUILayout.Button("X", EditorStyles.miniButtonLeft, miniButtonWidth)) + { + if (EditorUtility.DisplayDialog("Delete", "Are you sure you want to delete this element?", "Delete", "Cancel")) + { + WorldLinkRequest.DeleteWorldLinkAsync(worldStorageServer, Guid.Parse(UUID), (response) => + { + WorldStorageWindowSingleton.GetWorldLinks(); + }); + } + } + GUI.backgroundColor = ori; + + EditorGUILayout.EndHorizontal(); + } + EditorGUILayout.EndFoldoutHeaderGroup(); + #endregion + + // + GUILayout.EndVertical(); + } + + // ########################################################### + // Get elements from current server + // ########################################################### + #region Helpers + static public string GetUUIDFromString(string text) + { + if (!text.Contains("[")) return null; + else + { + // extract the UUID + return text.Split('[', ']')[1]; + } + } + public void GetCreators() + { + // Get all objects + Debug.Log("Get all creators id"); + TrackableRequest.GetTrackablesAsync(worldStorageServer, (response) => + { + creators.Clear(); + foreach (var item in response.result) + { + if (!creators.Contains(item.CreatorUUID.ToString())) creators.Add(item.CreatorUUID.ToString()); + } + }); + } + + static public (string, string) GetFirstKeyValueTags(KeyvalueTagList dict) + { + if (dict.Count >= 1) + { + // Get the first value in account (demo) + foreach (var item in dict) + { + string key1 = item.Key; + if (item.Value.Count >= 1) + { + string value1 = item.Value[0]; + return (key1, value1); + } + } + } + return ("", ""); + } + + public void GetTrackables() + { + // Get all objects + Debug.Log("Get all server objects"); + trackables.Clear(); + repaint = true; + TrackableRequest.GetTrackablesAsync(worldStorageServer, (response) => + { + Debug.Log("Get objects num = " + response.result.Count); + foreach (var item in response.result) + { + if (filterByKeyValueTag != "") + { + var first = GetFirstKeyValueTags(item.KeyvalueTags); + if (first.Item1.ToLower() != "group" || first.Item2 != filterByKeyValueTag) continue; + } + if (!string.IsNullOrEmpty(item.Name)) trackables.Add(item.Name + " [" + item.UUID.ToString() + "]"); + else trackables.Add(item.UUID.ToString()); + } + repaint = true; + }); + } + + public void GetWorldAnchors() + { + // Get all objects + Debug.Log("Get all server objects"); + anchors.Clear(); + repaint = true; + WorldAnchorRequest.GetWorldAnchorsAsync(worldStorageServer, (response) => + { + foreach (var item in response.result) + { + if (filterByKeyValueTag != "") + { + var first = GetFirstKeyValueTags(item.KeyvalueTags); + if (first.Item1.ToLower() != "group" || first.Item2 != filterByKeyValueTag) continue; + } + if (!string.IsNullOrEmpty(item.Name)) anchors.Add(item.Name + " [" + item.UUID.ToString() + "]"); + else anchors.Add(item.UUID.ToString()); + } + repaint = true; + }); + } + + public void GetWorldLinks() + { + // Get all objects + Debug.Log("Get all server objects"); + links.Clear(); + repaint = true; + WorldLinkRequest.GetWorldLinksAsync(worldStorageServer, (response) => + { + foreach (var item in response.result) + { + links.Add(item.UUID.ToString()); + } + repaint = true; + }); + } + #endregion + } +} \ No newline at end of file diff --git a/Editor/Scripts/Windows/WorldStorageWindow.cs.meta b/Editor/Scripts/Windows/WorldStorageWindow.cs.meta new file mode 100644 index 0000000..ec99c51 --- /dev/null +++ b/Editor/Scripts/Windows/WorldStorageWindow.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: a1647df9b48bf4f49a664a929fff57ff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - m_ViewDataDictionary: {instanceID: 0} + - worldStorageServer: {fileID: 11400000, guid: 4f997253243de534dad12937f1284975, type: 2} + - worldStorageUser: {fileID: 11400000, guid: c0696089e4a855b46ad490437919b1e8, type: 2} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/WorldStoragePrefabs.cs b/Editor/Scripts/WorldStoragePrefabs.cs new file mode 100644 index 0000000..be46c26 --- /dev/null +++ b/Editor/Scripts/WorldStoragePrefabs.cs @@ -0,0 +1,36 @@ +// +// ARF - Augmented Reality Framework (ETSI ISG ARF) +// +// Copyright 2024 ETSI +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Last change: July 2022 +// + +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace ETSI.ARF.WorldStorage.UI.Prefabs +{ + [System.Serializable] + [CreateAssetMenu(fileName = "ARFPrefabs", menuName = "ARF World Storage/Setup for Visuals (prefabs)", order = 1)] + public class WorldStoragePrefabs : ScriptableObject + { + [SerializeField] public GameObject trackablePrefab; + [SerializeField] public GameObject worldAnchorPrefab; + [SerializeField] public GameObject worldLinkPrefab; + } +} \ No newline at end of file diff --git a/Editor/Scripts/WorldStoragePrefabs.cs.meta b/Editor/Scripts/WorldStoragePrefabs.cs.meta new file mode 100644 index 0000000..c921b23 --- /dev/null +++ b/Editor/Scripts/WorldStoragePrefabs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1aec4cd1383f70e4092183ea55088e8e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Scripts/WorldStorageServerEditor.cs b/Editor/Scripts/WorldStorageServerEditor.cs index 7cbc404..98b8311 100644 --- a/Editor/Scripts/WorldStorageServerEditor.cs +++ b/Editor/Scripts/WorldStorageServerEditor.cs @@ -15,159 +15,50 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// Last change: July 2024 +// Last change: June 2022 // using System.Collections; +using System.Collections.Generic; + using UnityEngine; using UnityEditor; -using ETSI.ARF.OpenAPI; -using ETSI.ARF.WorldStorage; -using ETSI.ARF.WorldStorage.REST; - -[CustomEditor(typeof(WorldStorageServer))] -public class WorldStorageServerEditor : Editor +namespace ETSI.ARF.WorldStorage.UI { - WorldStorageServer server; - - private string state = ""; - private string version = ""; - - private string test = ""; - - private Queue handleResponseQueue = new Queue(); - - private ResponseObject pendingTest = null; - private ResponseObject pendingState = null; - private ResponseObject pendingVersion = null; - - public void OnEnable() + [CustomEditor(typeof(WorldStorageServer))] + public class WorldStorageServerEditor : UnityEditor.Editor { - server = (WorldStorageServer)target; - } - - public override void OnInspectorGUI() - { - serializedObject.Update(); - - DrawDefaultInspector(); - EditorGUILayout.Space(); - - if (GUILayout.Button("Test server")) - { - TestPing(); - } - EditorGUILayout.LabelField("Test Response", test); - - EditorGUILayout.Space(); + WorldStorageServer worldStorageServer; + WorldStorageWindow win; - if (GUILayout.Button("Query server")) + public void OnEnable() { - QueryServer(); + worldStorageServer = (WorldStorageServer)target; } - EditorGUILayout.LabelField("Server State", state); - EditorGUILayout.LabelField("OpenAPI Version", version); - - if (handleResponseQueue.Count > 0) + public override void OnInspectorGUI() { - object o = handleResponseQueue.Dequeue(); - if (o.Equals(pendingTest)) - { - ResponseObject response = o as ResponseObject; - Debug.Log($"Get '{response.result}' from server"); + serializedObject.Update(); - test = response.result; - pendingTest = null; - EditorUtility.SetDirty(target); - } - else if (o.Equals(pendingState)) - { - ResponseObject response = o as ResponseObject; - Debug.Log($"Get '{response.result}' from server"); + Color ori = GUI.backgroundColor; - state = response.result; - pendingState = null; - EditorUtility.SetDirty(target); - } - else if (o.Equals(pendingVersion)) - { - ResponseObject response = o as ResponseObject; - Debug.Log($"Get '{response.result}' from server"); + GUILayout.Label("Copyright(c) 2022, ETSI - ARF"); + EditorGUILayout.Space(); + GUILayout.Label("Parameters:", EditorStyles.boldLabel); + DrawDefaultInspector(); + EditorGUILayout.Space(); - version = response.result; - pendingVersion = null; - EditorUtility.SetDirty(target); - } - else + // open window button + GUI.backgroundColor = WorldStorageWindow.arfColors[1]; + if (GUILayout.Button("Open World Storage Window...")) { - Debug.Log("Unsupported response!"); + Debug.Log("Open Main ARF Window"); + win = EditorWindow.GetWindow(typeof(WorldStorageWindow), false, "ETSI ARF - Authoring Editor") as WorldStorageWindow; + win.worldStorageServer = worldStorageServer; + win.worldStorageUser = worldStorageServer.currentUser; } + GUI.backgroundColor = ori; } } - - public override bool RequiresConstantRepaint() - { - return handleResponseQueue.Count > 0; - } - - void OnSceneGUI() - { - Debug.Log("OnSceneGUI"); - } - - private void TestPing() - { - test = ""; - EditorUtility.SetDirty(target); - - if (server == null) - { - Debug.LogError("No server defined!"); - return; - } - - //string response = AdminRequest.PingSync(server); - //EditorUtility.DisplayDialog("Test Server", $"Get '{response}' from server", "OK"); - - if (pendingTest != null) - { - pendingTest.Cancel(); - } - - pendingTest = AdminRequest.PingAsync(server, (response) => - { - handleResponseQueue.Enqueue(response); - Debug.Log($"Request Time: { response.requestTime.ToLongTimeString() } / Total Time: { response.DeltaTime.TotalMilliseconds }ms\n\nContent:\n{ response.result }"); - }); - - Debug.Log("Starting request @ time: " + pendingTest.requestTime.ToLongTimeString() + "..."); - } - - private void QueryServer() - { - version = ""; - state = ""; - - if (pendingState != null) - { - pendingState.Cancel(); - } - - pendingState = AdminRequest.AdminAsync(server, (response) => - { - handleResponseQueue.Enqueue(response); - }); - - if (pendingVersion != null) - { - pendingVersion.Cancel(); - } - - pendingVersion = AdminRequest.VersionAsync(server, (response) => - { - handleResponseQueue.Enqueue(response); - }); - } } \ No newline at end of file diff --git a/Editor/Scripts/WorldStorageServerEditor.cs.meta b/Editor/Scripts/WorldStorageServerEditor.cs.meta index 058d2a8..2cc100f 100644 --- a/Editor/Scripts/WorldStorageServerEditor.cs.meta +++ b/Editor/Scripts/WorldStorageServerEditor.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: e5c9b5bdbeaab49729133f4ac17ded99 +guid: 878ee3c4c6608354f90354fd159f4e04 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/Scripts/WorldStorageUserEditor.cs b/Editor/Scripts/WorldStorageUserEditor.cs index 7de785f..61710a0 100644 --- a/Editor/Scripts/WorldStorageUserEditor.cs +++ b/Editor/Scripts/WorldStorageUserEditor.cs @@ -1,7 +1,7 @@ // // ARF - Augmented Reality Framework (ETSI ISG ARF) // -// Copyright 2022 ETSI +// Copyright 2024 ETSI // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,37 +15,48 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// Last change: June 2022 +// Last change: June 2024 // using System.Collections; using System.Collections.Generic; + using UnityEngine; using UnityEditor; -using ETSI.ARF.WorldStorage; - -[CustomEditor(typeof(WorldStorageUser))] -public class WorldStorageUserEditor : Editor +namespace ETSI.ARF.WorldStorage.UI { - WorldStorageUser user; - - public void OnEnable() - { - user = (WorldStorageUser)target; - } - - public override void OnInspectorGUI() + [CustomEditor(typeof(WorldStorageUser))] + public class WorldStorageUserEditor : UnityEditor.Editor { - serializedObject.Update(); + WorldStorageUser worldStorageUser; + WorldStorageWindow win; - DrawDefaultInspector(); - EditorGUILayout.Space(); + public void OnEnable() + { + worldStorageUser = (WorldStorageUser)target; + } - if (GUILayout.Button("Generate New Creator UUID")) + public override void OnInspectorGUI() { - user.UUID = System.Guid.NewGuid().ToString(); - EditorUtility.SetDirty(target); + serializedObject.Update(); + + Color ori = GUI.backgroundColor; + + GUILayout.Label("Copyright(c) 2022, ETSI - ARF"); + EditorGUILayout.Space(); + GUILayout.Label("Parameters:", EditorStyles.boldLabel); + DrawDefaultInspector(); + EditorGUILayout.Space(); + + // creator UUID button + GUI.backgroundColor = WorldStorageWindow.arfColors[1]; + if (GUILayout.Button("Generate New Creator UUID")) + { + worldStorageUser.UUID = System.Guid.NewGuid().ToString(); + if (win != null) win.worldStorageUser.UUID = worldStorageUser.UUID; + } + GUI.backgroundColor = ori; } } -} +} \ No newline at end of file diff --git a/Editor/Scripts/WorldStorageUserEditor.cs.meta b/Editor/Scripts/WorldStorageUserEditor.cs.meta index 0efd092..fda722e 100644 --- a/Editor/Scripts/WorldStorageUserEditor.cs.meta +++ b/Editor/Scripts/WorldStorageUserEditor.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 27356e11ca7a946a6a6cf289f784ee18 +guid: 134a71a4b493ae1468ea8de88c99135c MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/etsi.isg.arf.worldstorage.Editor.asmdef b/Editor/etsi.isg.arf.worldstorage.Editor.asmdef index ab26015..b49a6d7 100644 --- a/Editor/etsi.isg.arf.worldstorage.Editor.asmdef +++ b/Editor/etsi.isg.arf.worldstorage.Editor.asmdef @@ -2,7 +2,8 @@ "name": "etsi.isg.arf.worldstorage.editor", "rootNamespace": "", "references": [ - "GUID:99fdaa6f193b69346bfc8863615f98f0" + "GUID:99fdaa6f193b69346bfc8863615f98f0", + "GUID:6055be8ebefd69e48b49212b09b47b2f" ], "includePlatforms": [ "Editor" diff --git a/Runtime/Prefabs.meta b/Runtime/Prefabs.meta new file mode 100644 index 0000000..3afe3fd --- /dev/null +++ b/Runtime/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 58d625e15ff264e479d393186a4a9827 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Prefabs/ARFTrackable.prefab b/Runtime/Prefabs/ARFTrackable.prefab new file mode 100644 index 0000000..678ddae --- /dev/null +++ b/Runtime/Prefabs/ARFTrackable.prefab @@ -0,0 +1,835 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1239500166128132140 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1814829793678878270} + m_Layer: 0 + m_Name: ARFTrackable + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1814829793678878270 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1239500166128132140} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4532241398218188797} + - {fileID: 33536572583887604} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1389085265039543899 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 788171341007892784} + - component: {fileID: 8839914115087242523} + - component: {fileID: 4246121306890513542} + - component: {fileID: 1020142642249578057} + m_Layer: 0 + m_Name: Y + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &788171341007892784 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1389085265039543899} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0.1, z: 0} + m_LocalScale: {x: 0.020000001, y: 0.05, z: 0.020000001} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4532241398218188797} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8839914115087242523 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1389085265039543899} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &4246121306890513542 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1389085265039543899} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 19de5bd9483daf448a5fab21d3eecba3, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!136 &1020142642249578057 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1389085265039543899} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!1 &1687101261560852242 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 377487265314945344} + - component: {fileID: 6822513350628080072} + - component: {fileID: 6739960153126183626} + - component: {fileID: 8765868915607131294} + m_Layer: 0 + m_Name: Z + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &377487265314945344 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1687101261560852242} + m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 0, z: 0.1} + m_LocalScale: {x: 0.020000001, y: 0.05000001, z: 0.019999998} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4532241398218188797} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!33 &6822513350628080072 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1687101261560852242} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6739960153126183626 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1687101261560852242} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1b6b868784cd25c46a90fe7b882fddb2, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!136 &8765868915607131294 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1687101261560852242} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!1 &1823986580348874447 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1436432047471570793} + - component: {fileID: 5158975352210721371} + - component: {fileID: 4673833591676428792} + - component: {fileID: 961187375770271614} + m_Layer: 0 + m_Name: X + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1436432047471570793 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1823986580348874447} + m_LocalRotation: {x: -0, y: -0, z: 0.7071068, w: 0.7071068} + m_LocalPosition: {x: 0.1, y: 0, z: 0} + m_LocalScale: {x: 0.019999998, y: 0.05000001, z: 0.020000001} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4532241398218188797} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 90} +--- !u!33 &5158975352210721371 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1823986580348874447} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &4673833591676428792 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1823986580348874447} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0c6a9f85031693343a9e37c4a08627e9, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!136 &961187375770271614 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1823986580348874447} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!1 &4451045791079530586 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2888022835692577799} + - component: {fileID: 3434672324534858807} + - component: {fileID: 420668000673399792} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2888022835692577799 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4451045791079530586} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.001, y: 0.001, z: 0.001} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 33536572583887604} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -0.025} + m_SizeDelta: {x: 250, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3434672324534858807 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4451045791079530586} + m_CullTransparentMesh: 1 +--- !u!114 &420668000673399792 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4451045791079530586} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: 'Name: + + UUID:' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 16 + m_fontSizeBase: 16 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &5897666007833324009 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8156859587808685068} + - component: {fileID: 1360188677730577841} + - component: {fileID: 3860478840123770047} + m_Layer: 5 + m_Name: Headline + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8156859587808685068 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5897666007833324009} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.001, y: 0.001, z: 0.001} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 33536572583887604} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0.02} + m_SizeDelta: {x: 250, y: 25} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1360188677730577841 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5897666007833324009} + m_CullTransparentMesh: 1 +--- !u!114 &3860478840123770047 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5897666007833324009} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: AR Trackable + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 1 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &8182691244837652424 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4532241398218188797} + m_Layer: 0 + m_Name: Axe + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4532241398218188797 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8182691244837652424} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8225488253825437765} + - {fileID: 1436432047471570793} + - {fileID: 788171341007892784} + - {fileID: 377487265314945344} + m_Father: {fileID: 1814829793678878270} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &8225488253825437761 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8225488253825437765} + - component: {fileID: 8225488253825437764} + - component: {fileID: 8225488253825437763} + - component: {fileID: 8225488253825437762} + m_Layer: 0 + m_Name: Center + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8225488253825437765 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8225488253825437761} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.1, y: 0.1, z: 0.1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 4532241398218188797} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8225488253825437764 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8225488253825437761} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &8225488253825437763 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8225488253825437761} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 4f607925b7a7fcc44806b35f5aa087a4, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &8225488253825437762 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8225488253825437761} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &8292506020522815698 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 33536572583887604} + - component: {fileID: 1417027443369488948} + - component: {fileID: 1035955511594240086} + - component: {fileID: 5661858723465099382} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &33536572583887604 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8292506020522815698} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8156859587808685068} + - {fileID: 2888022835692577799} + m_Father: {fileID: 1814829793678878270} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0.1263, y: -0.1} + m_SizeDelta: {x: 640, y: 480} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!223 &1417027443369488948 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8292506020522815698} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 2 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 25 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &1035955511594240086 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8292506020522815698} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 1 +--- !u!114 &5661858723465099382 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8292506020522815698} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 diff --git a/Runtime/Prefabs/ARFTrackable.prefab.meta b/Runtime/Prefabs/ARFTrackable.prefab.meta new file mode 100644 index 0000000..817771e --- /dev/null +++ b/Runtime/Prefabs/ARFTrackable.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 889bc3e43608e504c977b93ba5f8ed37 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Prefabs/ARFWorldAnchor.prefab b/Runtime/Prefabs/ARFWorldAnchor.prefab new file mode 100644 index 0000000..cea4dce --- /dev/null +++ b/Runtime/Prefabs/ARFWorldAnchor.prefab @@ -0,0 +1,835 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1058305942658709743 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4263110725940009300} + - component: {fileID: 4129045750120536829} + - component: {fileID: 6557221987491350997} + m_Layer: 5 + m_Name: Headline + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4263110725940009300 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1058305942658709743} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.001, y: 0.001, z: 0.001} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 1497700213276983046} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0.02} + m_SizeDelta: {x: 250, y: 25} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4129045750120536829 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1058305942658709743} + m_CullTransparentMesh: 1 +--- !u!114 &6557221987491350997 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1058305942658709743} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: AR World Anchor + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 1 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &1525499792725534490 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6503384942250313519} + m_Layer: 0 + m_Name: Axe + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6503384942250313519 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1525499792725534490} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1622323168209334423} + - {fileID: 8595771872739495867} + - {fileID: 7950346510699467234} + - {fileID: 7032495084649945490} + m_Father: {fileID: 9046317383172441836} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1622323168209334419 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1622323168209334423} + - component: {fileID: 1622323168209334422} + - component: {fileID: 1622323168209334417} + - component: {fileID: 1622323168209334416} + m_Layer: 0 + m_Name: Center + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1622323168209334423 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1622323168209334419} + m_LocalRotation: {x: 0, y: 1, z: 0, w: 0} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.1, y: 0.1, z: 0.1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 6503384942250313519} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0} +--- !u!33 &1622323168209334422 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1622323168209334419} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &1622323168209334417 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1622323168209334419} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 730ea8fe50af5874fb3b990c534eaebc, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &1622323168209334416 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1622323168209334419} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &4529171925897838154 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2044833251513730170} + - component: {fileID: 8475275463028488054} + - component: {fileID: 3041298355498540117} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2044833251513730170 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4529171925897838154} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.001, y: 0.001, z: 0.001} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 1497700213276983046} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -0.025} + m_SizeDelta: {x: 250, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8475275463028488054 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4529171925897838154} + m_CullTransparentMesh: 1 +--- !u!114 &3041298355498540117 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4529171925897838154} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: 'Name: + + UUID:' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 16 + m_fontSizeBase: 16 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &8344222362070912960 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7032495084649945490} + - component: {fileID: 4182441150992537882} + - component: {fileID: 4119753123192799768} + - component: {fileID: 2090784007532835916} + m_Layer: 0 + m_Name: Z + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7032495084649945490 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8344222362070912960} + m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 0, z: 0.1} + m_LocalScale: {x: 0.020000001, y: 0.05000001, z: 0.019999998} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6503384942250313519} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!33 &4182441150992537882 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8344222362070912960} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &4119753123192799768 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8344222362070912960} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1b6b868784cd25c46a90fe7b882fddb2, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!136 &2090784007532835916 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8344222362070912960} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!1 &8473238451594182910 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9046317383172441836} + m_Layer: 0 + m_Name: ARFWorldAnchor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9046317383172441836 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8473238451594182910} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6503384942250313519} + - {fileID: 1497700213276983046} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &8638588117357457033 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7950346510699467234} + - component: {fileID: 2164195824166614473} + - component: {fileID: 6793727845488397396} + - component: {fileID: 7677843500006282907} + m_Layer: 0 + m_Name: Y + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7950346510699467234 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8638588117357457033} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0.1, z: 0} + m_LocalScale: {x: 0.020000001, y: 0.05, z: 0.020000001} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6503384942250313519} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &2164195824166614473 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8638588117357457033} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6793727845488397396 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8638588117357457033} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 19de5bd9483daf448a5fab21d3eecba3, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!136 &7677843500006282907 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8638588117357457033} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!1 &8828373246506081872 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1497700213276983046} + - component: {fileID: 8595258003796922682} + - component: {fileID: 3895121440785909528} + - component: {fileID: 2278103916936109689} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1497700213276983046 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8828373246506081872} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4263110725940009300} + - {fileID: 2044833251513730170} + m_Father: {fileID: 9046317383172441836} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0.1263, y: -0.1} + m_SizeDelta: {x: 640, y: 480} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!223 &8595258003796922682 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8828373246506081872} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 2 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 25 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &3895121440785909528 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8828373246506081872} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 1 +--- !u!114 &2278103916936109689 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8828373246506081872} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!1 &9076285480843021853 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8595771872739495867} + - component: {fileID: 2539246307318246025} + - component: {fileID: 2628309207522230570} + - component: {fileID: 7634649738335838124} + m_Layer: 0 + m_Name: X + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8595771872739495867 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9076285480843021853} + m_LocalRotation: {x: -0, y: -0, z: 0.7071068, w: 0.7071068} + m_LocalPosition: {x: 0.1, y: 0, z: 0} + m_LocalScale: {x: 0.019999998, y: 0.05000001, z: 0.020000001} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6503384942250313519} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 90} +--- !u!33 &2539246307318246025 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9076285480843021853} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2628309207522230570 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9076285480843021853} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0c6a9f85031693343a9e37c4a08627e9, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!136 &7634649738335838124 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9076285480843021853} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} diff --git a/Runtime/Prefabs/ARFWorldAnchor.prefab.meta b/Runtime/Prefabs/ARFWorldAnchor.prefab.meta new file mode 100644 index 0000000..898f39e --- /dev/null +++ b/Runtime/Prefabs/ARFWorldAnchor.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 832a64407eb5c8249bb8e4a074649918 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Prefabs/ARFWorldLink.prefab b/Runtime/Prefabs/ARFWorldLink.prefab new file mode 100644 index 0000000..077a9e1 --- /dev/null +++ b/Runtime/Prefabs/ARFWorldLink.prefab @@ -0,0 +1,555 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1239500166128132140 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1814829793678878270} + - component: {fileID: 2766171691247251799} + m_Layer: 0 + m_Name: ARFWorldLink + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1814829793678878270 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1239500166128132140} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4532241398218188797} + - {fileID: 33536572583887604} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2766171691247251799 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1239500166128132140} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 33fce8a1d8d349d47b8565dfe031b6b1, type: 3} + m_Name: + m_EditorClassIdentifier: + fromElement: {fileID: 0} + toElement: {fileID: 0} +--- !u!1 &4451045791079530586 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2888022835692577799} + - component: {fileID: 3434672324534858807} + - component: {fileID: 420668000673399792} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2888022835692577799 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4451045791079530586} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.001, y: 0.001, z: 0.001} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 33536572583887604} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -0.025} + m_SizeDelta: {x: 250, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3434672324534858807 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4451045791079530586} + m_CullTransparentMesh: 1 +--- !u!114 &420668000673399792 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4451045791079530586} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: 'UUID: + + From: + + To:' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 16 + m_fontSizeBase: 16 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &5897666007833324009 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8156859587808685068} + - component: {fileID: 1360188677730577841} + - component: {fileID: 3860478840123770047} + m_Layer: 5 + m_Name: Headline + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8156859587808685068 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5897666007833324009} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.001, y: 0.001, z: 0.001} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 33536572583887604} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0.02} + m_SizeDelta: {x: 250, y: 25} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1360188677730577841 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5897666007833324009} + m_CullTransparentMesh: 1 +--- !u!114 &3860478840123770047 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5897666007833324009} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: AR World Link + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 1 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &8182691244837652424 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4532241398218188797} + m_Layer: 0 + m_Name: Axe + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4532241398218188797 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8182691244837652424} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8225488253825437765} + m_Father: {fileID: 1814829793678878270} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &8225488253825437761 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8225488253825437765} + - component: {fileID: 8225488253825437764} + - component: {fileID: 8225488253825437763} + - component: {fileID: 8225488253825437762} + m_Layer: 0 + m_Name: Center + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8225488253825437765 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8225488253825437761} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.1, y: 0.1, z: 0.1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 4532241398218188797} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8225488253825437764 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8225488253825437761} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &8225488253825437763 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8225488253825437761} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: ce02d83032448a945ac827316ba8bb87, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &8225488253825437762 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8225488253825437761} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &8292506020522815698 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 33536572583887604} + - component: {fileID: 1417027443369488948} + - component: {fileID: 1035955511594240086} + - component: {fileID: 5661858723465099382} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &33536572583887604 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8292506020522815698} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8156859587808685068} + - {fileID: 2888022835692577799} + m_Father: {fileID: 1814829793678878270} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0.1263, y: -0.1} + m_SizeDelta: {x: 640, y: 480} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!223 &1417027443369488948 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8292506020522815698} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 2 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 25 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &1035955511594240086 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8292506020522815698} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 1 +--- !u!114 &5661858723465099382 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8292506020522815698} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 diff --git a/Runtime/Prefabs/ARFWorldLink.prefab.meta b/Runtime/Prefabs/ARFWorldLink.prefab.meta new file mode 100644 index 0000000..7c41f4e --- /dev/null +++ b/Runtime/Prefabs/ARFWorldLink.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fbd37f7ee889c994a913eeca05e0501f +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Resources.meta b/Runtime/Resources.meta new file mode 100644 index 0000000..f531d88 --- /dev/null +++ b/Runtime/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f07b85312ef176543b32402edd2bdb8a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Resources/ARFPrefabs.asset b/Runtime/Resources/ARFPrefabs.asset new file mode 100644 index 0000000..9190b5a --- /dev/null +++ b/Runtime/Resources/ARFPrefabs.asset @@ -0,0 +1,17 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +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: 1aec4cd1383f70e4092183ea55088e8e, type: 3} + m_Name: ARFPrefabs + m_EditorClassIdentifier: + trackablePrefab: {fileID: 1239500166128132140, guid: 889bc3e43608e504c977b93ba5f8ed37, type: 3} + worldAnchorPrefab: {fileID: 8473238451594182910, guid: 832a64407eb5c8249bb8e4a074649918, type: 3} + worldLinkPrefab: {fileID: 1239500166128132140, guid: fbd37f7ee889c994a913eeca05e0501f, type: 3} diff --git a/Runtime/Resources/ARFPrefabs.asset.meta b/Runtime/Resources/ARFPrefabs.asset.meta new file mode 100644 index 0000000..a377b92 --- /dev/null +++ b/Runtime/Resources/ARFPrefabs.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cc22d9e73b4dcca4da1f7bdd0321a3d2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/GraphEditor.meta b/Runtime/Scripts/GraphEditor.meta new file mode 100644 index 0000000..de46d1d --- /dev/null +++ b/Runtime/Scripts/GraphEditor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b080491b321d38844bf995a06e92b5e0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/GraphEditor/AttachToWorldAnchor.cs b/Runtime/Scripts/GraphEditor/AttachToWorldAnchor.cs new file mode 100644 index 0000000..852b8a7 --- /dev/null +++ b/Runtime/Scripts/GraphEditor/AttachToWorldAnchor.cs @@ -0,0 +1,29 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace ETSI.ARF.WorldStorage.UI +{ + [ExecuteAlways] + public class AttachToWorldAnchor : MonoBehaviour + { + public GameObject worldAnchor; + public bool autoUpdate = true; + + private void Update() + { + if (autoUpdate && worldAnchor != null) + { + transform.position = worldAnchor.transform.position; + transform.rotation = worldAnchor.transform.rotation; + } + } + + void OnDrawGizmos() + { +#if UNITY_EDITOR + // do something... +#endif + } + } +} diff --git a/Runtime/Scripts/GraphEditor/AttachToWorldAnchor.cs.meta b/Runtime/Scripts/GraphEditor/AttachToWorldAnchor.cs.meta new file mode 100644 index 0000000..b568971 --- /dev/null +++ b/Runtime/Scripts/GraphEditor/AttachToWorldAnchor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 53275cee00d69114f926dc2b69bb4e53 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/GraphEditor/Data.cs b/Runtime/Scripts/GraphEditor/Data.cs new file mode 100644 index 0000000..57da603 --- /dev/null +++ b/Runtime/Scripts/GraphEditor/Data.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using ETSI.ARF.OpenAPI.WorldStorage; + +namespace ETSI.ARF.OpenAPI +{ + public struct Data + { + public Dictionary list; + + public int Count => list.Count; + public int PreCount { get; set; } + }; + +} diff --git a/Runtime/Scripts/GraphEditor/Data.cs.meta b/Runtime/Scripts/GraphEditor/Data.cs.meta new file mode 100644 index 0000000..f62618b --- /dev/null +++ b/Runtime/Scripts/GraphEditor/Data.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb8e8851570d3a14883c7798cbe1e1da +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/GraphEditor/LinkVisual.cs b/Runtime/Scripts/GraphEditor/LinkVisual.cs new file mode 100644 index 0000000..2acf9d7 --- /dev/null +++ b/Runtime/Scripts/GraphEditor/LinkVisual.cs @@ -0,0 +1,36 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace ETSI.ARF.WorldStorage.UI +{ + [ExecuteAlways] + public class LinkVisual : MonoBehaviour + { + public GameObject fromElement, toElement; + + + private void Update() + { +#if UNITY_EDITOR + if (fromElement != null && toElement != null) transform.position = (fromElement.transform.position + toElement.transform.position) / 2; +#endif + } + + void OnDrawGizmos() + { +#if UNITY_EDITOR + if (fromElement != null && toElement != null) + { + // Draws a blue line from this transform to the target + Gizmos.color = Color.blue; + Gizmos.DrawLine(fromElement.transform.position, toElement.transform.position); + } + else + { + Debug.Log("Rien à tracer"); + } + } +#endif + } +} diff --git a/Runtime/Scripts/GraphEditor/LinkVisual.cs.meta b/Runtime/Scripts/GraphEditor/LinkVisual.cs.meta new file mode 100644 index 0000000..07696e6 --- /dev/null +++ b/Runtime/Scripts/GraphEditor/LinkVisual.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 33fce8a1d8d349d47b8565dfe031b6b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/GraphEditor/WorldStorageCollections.cs b/Runtime/Scripts/GraphEditor/WorldStorageCollections.cs new file mode 100644 index 0000000..e144bd4 --- /dev/null +++ b/Runtime/Scripts/GraphEditor/WorldStorageCollections.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using ETSI.ARF.OpenAPI.WorldStorage; +using UnityEngine; +using System.IO; +using ETSI.ARF.OpenAPI; + +namespace ETSI.ARF.WorldStorage +{ + public class WorldStorageCollections + { + // MongoDB collections + // Contains list after response from REST server + public Data trackables = new Data(); + public Data worldAnchors = new Data(); + public Data worldLinks = new Data(); + + public WorldStorageCollections() + { + trackables.list = new Dictionary(); + worldAnchors.list = new Dictionary(); + worldLinks.list = new Dictionary(); + } + } +} diff --git a/Runtime/Scripts/GraphEditor/WorldStorageCollections.cs.meta b/Runtime/Scripts/GraphEditor/WorldStorageCollections.cs.meta new file mode 100644 index 0000000..c15e911 --- /dev/null +++ b/Runtime/Scripts/GraphEditor/WorldStorageCollections.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a5b322b539094934193f20b797fab02a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/GraphEditor/WorldStorageRequest.cs b/Runtime/Scripts/GraphEditor/WorldStorageRequest.cs new file mode 100644 index 0000000..a770667 --- /dev/null +++ b/Runtime/Scripts/GraphEditor/WorldStorageRequest.cs @@ -0,0 +1,167 @@ +// The Fraunhofer HHI Unity Framework +// ___________ .__ _____ ___ ___ ___ ___ .___ +// \_ _____/___________ __ __ ____ | |__ _____/ ____\___________ / | \ / | \| | +// | __) \_ __ \__ \ | | \/ \| | \ / _ \ __\/ __ \_ __ \ / ~ \/ ~ \ | +// | \ | | \// __ \| | / | \ Y ( <_> ) | \ ___/| | \/ \ Y /\ Y / | +// \___ / |__| (____ /____/|___| /___| /\____/|__| \___ >__| \___|_ / \___|_ /|___| +// \/ \/ \/ \/ \/ \/ \/ +// (C) Fraunhofer HHI, 2024 + +using System; +using System.IO; +using System.Net; +using System.Collections.Generic; +using System.Threading; +using System.Drawing; +using System.Threading.Tasks; +using UnityEngine; + +using ETSI.ARF.OpenAPI; +using ETSI.ARF.OpenAPI.WorldStorage; +using ETSI.ARF.WorldStorage.REST; + +namespace ETSI.ARF.WorldStorage +{ + /// + /// Manager class for OpenAPI REST calls. + /// This class insert create a response object with cancellation token for all call. + /// Also usefull for measuring the request-response time. + /// + public class WorldStorageRequest : WorldStorageCollections + { + private WorldStorageServer wsServer; + private WorldStorageClient apiClient; + private string serverUri; + + public string URI => serverUri; + public WorldStorageClient Client => apiClient; + + public WorldStorageRequest(WorldStorageServer server) : base() + { + wsServer = server; + serverUri = wsServer.URI; + var httpClient = new UnityWebRequestHttpClient(serverUri); + apiClient = new WorldStorageClient(httpClient); + } + + public WorldStorageRequest(string uri) : base() + { + wsServer = new WorldStorageServer(); + wsServer.basePath = uri; + wsServer.port = 0; + serverUri = uri; + var httpClient = new UnityWebRequestHttpClient(serverUri); + apiClient = new WorldStorageClient(httpClient); + } + + // + // Callback method + // Call the callback method defined by the calling class when the result is there. + // + #region Callbacks + private void ReceiveTextCallback(Task t, object id) + { + if (t.IsCompleted) + { + string res = t.Result; + + ResponseObject o = (ResponseObject)id; + o.responseTime = DateTime.Now; + o.result = res; + Debug.Log($"[REST] Server Response = {o.result} (#{o.transactionId}, {o.message})"); + + o.callback?.Invoke(o); + } + else Debug.Log("[REST] OpenAPI Timeout!"); + } + + private void ReceiveTrackableCallback(Task t, object id) + { + if (t.IsCompleted) + { + ResponseObject o = (ResponseObject)id; + o.responseTime = DateTime.Now; + o.result = t.Result; + Debug.Log($"[REST] Server Response = Got asset (#{o.transactionId}, {o.message})"); + + o.callback?.Invoke(o); + } + else Debug.Log("[REST] OpenAPI Timeout!"); + } + #endregion + + // + // Admin requests + // + #region Handle admin requests + public string Ping() => apiClient.GetPing(); + + public ResponseObject PingAsync(Action> func) + { + return AdminRequest.PingAsync(wsServer, func); + } + + public string Status() => apiClient.GetAdmin(); + + public ResponseObject StatusAsync(Action> func) + { + return AdminRequest.AdminAsync(wsServer, func); + } + + public string Version() => apiClient.GetVersion(); + public Task GetVersion() => apiClient.GetVersionAsync(); + + public ResponseObject VersionAsync(Action> func) + { + return AdminRequest.VersionAsync(wsServer, func); + } + #endregion + + // + // TRACKABLES + // + #region Trackables + + //public Task GetNumOfAssets() => apiClient.NumOfAssetsAsync(); + //public bool IsAssetExists(Guid id) => apiClient.IsAssetId(id); + public ResponseObject AddTrackableAsync(Action> func, Trackable trackable) + { + return TrackableRequest.CreateTrackableAsync(wsServer, trackable, func); + } + + public ResponseObject DeleteTrackableAsync(Action> func, Guid id) + { + return TrackableRequest.DeleteTrackableAsync(wsServer, id, func); + } + + public ResponseObject ModifyTrackableAsync(Action> func, Trackable trackable) + { + return TrackableRequest.UpdateTrackableAsync(wsServer, trackable, func); + } + + public ResponseObject GetTrackableByIdAsync(Action> func, Guid id) + { + return TrackableRequest.GetTrackableAsync(wsServer, id, func); + } + + public ResponseObject> GetTrackableListAsync(Action>> func, int? max = 1) + { + return TrackableRequest.GetTrackablesAsync(wsServer, func); + } + #endregion + + + // + // Tools + // + #region Tools + public static float FloatParse(string stValue) + { + float v = 0; + float.TryParse(stValue, System.Globalization.NumberStyles.AllowDecimalPoint | System.Globalization.NumberStyles.AllowLeadingSign, System.Globalization.CultureInfo.InvariantCulture, out v); + return v; + } + + #endregion + } +} diff --git a/Runtime/Scripts/GraphEditor/WorldStorageRequest.cs.meta b/Runtime/Scripts/GraphEditor/WorldStorageRequest.cs.meta new file mode 100644 index 0000000..78ca79b --- /dev/null +++ b/Runtime/Scripts/GraphEditor/WorldStorageRequest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7dc0c152448d1cc41ade67c36e145ff2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: -- GitLab From 7d913d0689e3a1b0b6610286021e3f04d7af5845 Mon Sep 17 00:00:00 2001 From: jlacoche Date: Mon, 29 Jul 2024 11:30:29 +0200 Subject: [PATCH 09/13] Remove logs --- Editor/Scripts/Graph/ARFGraphView.cs | 2 -- Editor/Scripts/Windows/WorldGraphWindow.cs | 1 - 2 files changed, 3 deletions(-) diff --git a/Editor/Scripts/Graph/ARFGraphView.cs b/Editor/Scripts/Graph/ARFGraphView.cs index 196eaa4..e81b954 100644 --- a/Editor/Scripts/Graph/ARFGraphView.cs +++ b/Editor/Scripts/Graph/ARFGraphView.cs @@ -332,9 +332,7 @@ namespace ETSI.ARF.WorldStorage.UI List worldLinks = WorldLinkRequest.GetWorldLinksSync(worldStorageServer); foreach (WorldLink worldLink in worldLinks) { - Debug.Log("ports"); var portPair = GetPortsFromWorldLink(worldLink); - Debug.Log("edge " + (portPair.Key == null)+ " " + (portPair.Value == null)); ARFEdgeLink edge = portPair.Key.ConnectTo(portPair.Value); edge.worldLink = worldLink; edge.GUID = worldLink.UUID.ToString(); diff --git a/Editor/Scripts/Windows/WorldGraphWindow.cs b/Editor/Scripts/Windows/WorldGraphWindow.cs index c844cb4..02a81db 100644 --- a/Editor/Scripts/Windows/WorldGraphWindow.cs +++ b/Editor/Scripts/Windows/WorldGraphWindow.cs @@ -259,7 +259,6 @@ namespace ETSI.ARF.WorldStorage.Editor.Windows } List listA = WorldAnchorRequest.GetWorldAnchorsSync(worldStorageServer); - Debug.Log("Anchors " +listA.Count); foreach (WorldAnchor wa in listA) { if (wa.KeyvalueTags.ContainsKey("unityAuthoringPosX") && wa.KeyvalueTags.ContainsKey("unityAuthoringPosY")) -- GitLab From 3eb6aa6a08d1e96e15e32cfb69c64fc5bc2afc6e Mon Sep 17 00:00:00 2001 From: Sylvain Renault Date: Thu, 8 Aug 2024 18:01:53 +0200 Subject: [PATCH 10/13] Some namespace changes. --- Editor/Scripts/Windows/WorldStorageWindow.cs | 8 ++++---- Runtime/Scripts/OpenAPI/BaseClient.cs | 4 ++-- .../Scripts/OpenAPI/Generated/WorldStorageOpenAPI.cs | 10 +++++----- Runtime/Scripts/OpenAPI/ResponseObject.cs | 2 +- Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs | 2 +- Runtime/Scripts/OpenAPI/WorldStorageClient.cs | 6 +++--- .../Scripts/REST/RelocalizationInformationRequest.cs | 8 ++++---- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Editor/Scripts/Windows/WorldStorageWindow.cs b/Editor/Scripts/Windows/WorldStorageWindow.cs index 14d08cd..d8d036e 100644 --- a/Editor/Scripts/Windows/WorldStorageWindow.cs +++ b/Editor/Scripts/Windows/WorldStorageWindow.cs @@ -87,7 +87,7 @@ namespace ETSI.ARF.WorldStorage.UI public static void ShowWindow() { WorldStorageWindowSingleton = EditorWindow.GetWindow(typeof(WorldStorageWindow), false, WorldStorageWindow.winName) as WorldStorageWindow; - OpenAPI.ResponseObject ro = AdminRequest.PingAsync(WorldStorageWindowSingleton.worldStorageServer, (response) => + ResponseObject ro = AdminRequest.PingAsync(WorldStorageWindowSingleton.worldStorageServer, (response) => { WorldStorageWindowSingleton.ping = response.result; WorldStorageWindowSingleton.repaint = true; @@ -173,7 +173,7 @@ namespace ETSI.ARF.WorldStorage.UI ping = EditorGUILayout.TextField("Last Ping", ping); if (GUILayout.Button("Ping")) { - OpenAPI.ResponseObject ro = AdminRequest.PingAsync(worldStorageServer, (response) => + ResponseObject ro = AdminRequest.PingAsync(worldStorageServer, (response) => { ping = response.result; }); @@ -188,7 +188,7 @@ namespace ETSI.ARF.WorldStorage.UI if (GUILayout.Button("Get World Storage Sate")) { - OpenAPI.ResponseObject ro = AdminRequest.AdminAsync(worldStorageServer, (response) => + ResponseObject ro = AdminRequest.AdminAsync(worldStorageServer, (response) => { state = response.result; }); @@ -203,7 +203,7 @@ namespace ETSI.ARF.WorldStorage.UI if (GUILayout.Button("Get World Storage API Version")) { - OpenAPI.ResponseObject ro = AdminRequest.VersionAsync(worldStorageServer, (response) => + ResponseObject ro = AdminRequest.VersionAsync(worldStorageServer, (response) => { vers = response.result; }); diff --git a/Runtime/Scripts/OpenAPI/BaseClient.cs b/Runtime/Scripts/OpenAPI/BaseClient.cs index 83fa8c3..3bdc50b 100644 --- a/Runtime/Scripts/OpenAPI/BaseClient.cs +++ b/Runtime/Scripts/OpenAPI/BaseClient.cs @@ -13,7 +13,7 @@ namespace ETSI.ARF.OpenAPI public string lastJsonText; public long lastPayload; - protected void _prepareRequest(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpRequestMessage request, string url) + protected void _prepareRequest(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient client, System.Net.Http.HttpRequestMessage request, string url) { if (EnableClientLog) { @@ -22,7 +22,7 @@ namespace ETSI.ARF.OpenAPI } } - protected void _processResponse(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpResponseMessage response) + protected void _processResponse(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient client, System.Net.Http.HttpResponseMessage response) { lastJsonText = response.Content.ReadAsStringAsync().Result.ToString(); lastPayload = response.Content.Headers.ContentLength.Value; diff --git a/Runtime/Scripts/OpenAPI/Generated/WorldStorageOpenAPI.cs b/Runtime/Scripts/OpenAPI/Generated/WorldStorageOpenAPI.cs index a61b2ae..ba07b09 100644 --- a/Runtime/Scripts/OpenAPI/Generated/WorldStorageOpenAPI.cs +++ b/Runtime/Scripts/OpenAPI/Generated/WorldStorageOpenAPI.cs @@ -24,11 +24,11 @@ namespace ETSI.ARF.OpenAPI.WorldStorage [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class WorldStorageClient { - private ETSI.ARF.OpenAPI.IHttpClient _httpClient; + private ETSI.ARF.OpenAPI.WorldStorage.IHttpClient _httpClient; private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true); #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - public WorldStorageClient(ETSI.ARF.OpenAPI.IHttpClient httpClient) + public WorldStorageClient(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient httpClient) #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. { _httpClient = httpClient; @@ -45,9 +45,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage static partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); - partial void PrepareRequest(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpRequestMessage request, string url); - partial void PrepareRequest(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); - partial void ProcessResponse(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpResponseMessage response); + partial void PrepareRequest(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient client, System.Net.Http.HttpRequestMessage request, string url); + partial void PrepareRequest(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); + partial void ProcessResponse(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient client, System.Net.Http.HttpResponseMessage response); /// /// Test the server availability. diff --git a/Runtime/Scripts/OpenAPI/ResponseObject.cs b/Runtime/Scripts/OpenAPI/ResponseObject.cs index 2be59dc..6a37f19 100644 --- a/Runtime/Scripts/OpenAPI/ResponseObject.cs +++ b/Runtime/Scripts/OpenAPI/ResponseObject.cs @@ -13,7 +13,7 @@ using System.Collections.Generic; using System.Threading; using UnityEngine; -namespace ETSI.ARF.OpenAPI +namespace ETSI.ARF.OpenAPI.WorldStorage { public class CancelToken { diff --git a/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs b/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs index c70ef4c..a119a03 100644 --- a/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs +++ b/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs @@ -34,7 +34,7 @@ using System.Threading.Tasks; using UnityEngine; using UnityEngine.Networking; -namespace ETSI.ARF.OpenAPI +namespace ETSI.ARF.OpenAPI.WorldStorage { public interface IHttpClient { diff --git a/Runtime/Scripts/OpenAPI/WorldStorageClient.cs b/Runtime/Scripts/OpenAPI/WorldStorageClient.cs index 55a043e..d75cc6a 100644 --- a/Runtime/Scripts/OpenAPI/WorldStorageClient.cs +++ b/Runtime/Scripts/OpenAPI/WorldStorageClient.cs @@ -10,17 +10,17 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// public partial class WorldStorageClient : BaseClient { - partial void PrepareRequest(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpRequestMessage request, string url) + partial void PrepareRequest(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient client, System.Net.Http.HttpRequestMessage request, string url) { _prepareRequest(client, request, url); } - partial void PrepareRequest(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder) + partial void PrepareRequest(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder) { // do something... } - partial void ProcessResponse(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpResponseMessage response) + partial void ProcessResponse(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient client, System.Net.Http.HttpResponseMessage response) { _processResponse(client, response); } diff --git a/Runtime/Scripts/REST/RelocalizationInformationRequest.cs b/Runtime/Scripts/REST/RelocalizationInformationRequest.cs index 95470c6..5223399 100644 --- a/Runtime/Scripts/REST/RelocalizationInformationRequest.cs +++ b/Runtime/Scripts/REST/RelocalizationInformationRequest.cs @@ -81,7 +81,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage { public partial class WorldStorageClient { - public ETSI.ARF.OpenAPI.IHttpClient GetHttpClient() + public ETSI.ARF.OpenAPI.WorldStorage.IHttpClient GetHttpClient() { return _httpClient; } @@ -92,15 +92,15 @@ namespace ETSI.ARF.OpenAPI.WorldStorage } - public void PrepareRequest_(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpRequestMessage request, string url) + public void PrepareRequest_(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient client, System.Net.Http.HttpRequestMessage request, string url) { PrepareRequest(client, request, url); } - public void PrepareRequest_(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder) + public void PrepareRequest_(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder) { PrepareRequest(client, request, urlBuilder); } - public void ProcessResponse_(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpResponseMessage response) + public void ProcessResponse_(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient client, System.Net.Http.HttpResponseMessage response) { ProcessResponse(client, response); } -- GitLab From 6fbf9394c4d7b697e6d7ec870523cc83ec1cc52f Mon Sep 17 00:00:00 2001 From: Sylvain Renault Date: Thu, 5 Sep 2024 14:53:53 +0200 Subject: [PATCH 11/13] Title of window updated --- Editor/Scripts/Windows/WorldAnchorWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/Scripts/Windows/WorldAnchorWindow.cs b/Editor/Scripts/Windows/WorldAnchorWindow.cs index 649c1d0..2fb8dd0 100644 --- a/Editor/Scripts/Windows/WorldAnchorWindow.cs +++ b/Editor/Scripts/Windows/WorldAnchorWindow.cs @@ -212,7 +212,7 @@ namespace ETSI.ARF.WorldStorage.UI unit = (UnitSystem)EditorGUILayout.EnumPopup("Unit System:", unit); EditorGUILayout.Space(); - worldAnchorSize = EditorGUILayout.Vector3Field("Trackable Size:", worldAnchorSize); + worldAnchorSize = EditorGUILayout.Vector3Field("Anchor Size:", worldAnchorSize); EditorGUILayout.Space(); GUILayout.Label("Local CRS:"); -- GitLab From 6f1e544c2c2ee63d7e1c02c599d3fc0df0738319 Mon Sep 17 00:00:00 2001 From: Sylvain Renault Date: Mon, 16 Sep 2024 13:52:42 +0200 Subject: [PATCH 12/13] Bug fixed for the issue related to the new response format. Bug fixed for the issue with the header token (added a function in the IHttpInterface). --- Editor/Scripts/Graph/ARFGraphView.cs | 7 +- Editor/Scripts/Windows/GraphEditorWindow.cs | 6 +- Editor/Scripts/Windows/TrackableWindow.cs | 4 +- Editor/Scripts/Windows/WorldAnchorWindow.cs | 4 +- Editor/Scripts/Windows/WorldLinkWindow.cs | 4 +- Editor/Scripts/Windows/WorldStorageWindow.cs | 14 +- Runtime/Scenes/OpenAPITest.cs | 14 +- .../GraphEditor/WorldStorageRequest.cs | 8 +- .../OpenAPI/Generated/WorldStorageOpenAPI.cs | 845 ++++++++++++------ .../OpenAPI/UnityWebRequestHttpClient.cs | 29 +- .../REST/RelocalizationInformationRequest.cs | 28 +- Runtime/Scripts/REST/RequestBase.cs | 57 +- Runtime/Scripts/REST/TrackableRequest.cs | 34 +- Runtime/Scripts/REST/WorldAnchorRequest.cs | 32 +- Runtime/Scripts/REST/WorldLinkRequest.cs | 32 +- 15 files changed, 767 insertions(+), 351 deletions(-) diff --git a/Editor/Scripts/Graph/ARFGraphView.cs b/Editor/Scripts/Graph/ARFGraphView.cs index e81b954..7053c84 100644 --- a/Editor/Scripts/Graph/ARFGraphView.cs +++ b/Editor/Scripts/Graph/ARFGraphView.cs @@ -562,7 +562,7 @@ namespace ETSI.ARF.WorldStorage.UI TrackableRequest.CreateTrackableAsync(worldStorageServer, trackable, (response) => { //change the uuid in its edges, if there is a new edge to be added in the world storage it needs to have the correct uuid - String uuid = response.result; + String uuid = response.result.Message; uuid = uuid.Replace("\"", ""); foreach (ARFEdgeLink edge in aRFNodeTrackable.portIn.connections) @@ -592,8 +592,7 @@ namespace ETSI.ARF.WorldStorage.UI WorldAnchorRequest.CreateWorldAnchorAsync(worldStorageServer, worldAnchor, (response) => { - - String uuid = response.result; + String uuid = response.result.Message; //change the uuid in its edges, if there is a new edge to be added in the world storage it needs to have the correct uuid uuid = uuid.Replace("\"", ""); foreach (ARFEdgeLink edge in aRFNodeWorldAnchor.portIn.connections) @@ -659,7 +658,7 @@ namespace ETSI.ARF.WorldStorage.UI WorldLink worldLink = aRFEdgeLink.worldLink; WorldLinkRequest.CreateWorldLinkAsync(worldStorageServer, worldLink, (response) => { - string uuid = response.result; + string uuid = response.result.Message; uuid = uuid.Replace("\"", ""); aRFEdgeLink.worldLink.UUID = Guid.Parse(uuid); diff --git a/Editor/Scripts/Windows/GraphEditorWindow.cs b/Editor/Scripts/Windows/GraphEditorWindow.cs index d1d7aaf..33d15ae 100644 --- a/Editor/Scripts/Windows/GraphEditorWindow.cs +++ b/Editor/Scripts/Windows/GraphEditorWindow.cs @@ -524,7 +524,7 @@ namespace ETSI.ARF.WorldStorage.Editor.Windows WorldAnchorRequest.CreateWorldAnchorAsync(SaveInfo.instance.worldStorageServer, worldAnchor, (response) => { - String uuid = response.result; + String uuid = response.result.Message; //change the uuid in its edges, if there is a new edge to be added in the world storage it needs to have the correct uuid uuid = uuid.Replace("\"", ""); @@ -977,7 +977,7 @@ namespace ETSI.ARF.WorldStorage.Editor.Windows trackable.KeyvalueTags["unityAuthoringPosY"] = posY; TrackableRequest.CreateTrackableAsync(SaveInfo.instance.worldStorageServer, trackable, (response) => { - String uuid = response.result; + String uuid = response.result.Message; //change the uuid in its edges, if there is a new edge to be added in the world storage it needs to have the correct uuid uuid = uuid.Replace("\"", ""); @@ -1239,7 +1239,7 @@ namespace ETSI.ARF.WorldStorage.Editor.Windows { WorldLinkRequest.CreateWorldLinkAsync(SaveInfo.instance.worldStorageServer, worldLink, (response) => { - String uuid = response.result; + String uuid = response.result.Message; //Add the newly saved WorldLink to the SaveInfo singleton uuid = uuid.Replace("\"", ""); diff --git a/Editor/Scripts/Windows/TrackableWindow.cs b/Editor/Scripts/Windows/TrackableWindow.cs index 6360d7a..38b7bf6 100644 --- a/Editor/Scripts/Windows/TrackableWindow.cs +++ b/Editor/Scripts/Windows/TrackableWindow.cs @@ -166,7 +166,7 @@ namespace ETSI.ARF.WorldStorage.UI Trackable obj = GenerateObject(); TrackableRequest.UpdateTrackableAsync(worldStorageServer, obj, (response) => { - UUID = response.result; + UUID = response.result.Message; UUID = UUID.Trim('"'); //Bugfix: remove " from server return value if (WorldStorageWindow.WorldStorageWindowSingleton != null) @@ -313,7 +313,7 @@ namespace ETSI.ARF.WorldStorage.UI Trackable obj = GenerateObject(); TrackableRequest.CreateTrackableAsync(worldStorageServer, obj, (response) => { - UUID = response.result; + UUID = response.result.Message; UUID = UUID.Trim('"'); //Bugfix: remove " from server return value WorldStorageWindow.WorldStorageWindowSingleton.GetTrackables(); }); diff --git a/Editor/Scripts/Windows/WorldAnchorWindow.cs b/Editor/Scripts/Windows/WorldAnchorWindow.cs index 2fb8dd0..5e95874 100644 --- a/Editor/Scripts/Windows/WorldAnchorWindow.cs +++ b/Editor/Scripts/Windows/WorldAnchorWindow.cs @@ -163,7 +163,7 @@ namespace ETSI.ARF.WorldStorage.UI WorldAnchor obj = GenerateObject(); WorldAnchorRequest.UpdateWorldAnchorAsync(worldStorageServer, obj, (response) => { - UUID = response.result; + UUID = response.result.Message; UUID = UUID.Trim('"'); //Bugfix: remove " from server return value if (WorldStorageWindow.WorldStorageWindowSingleton != null) @@ -291,7 +291,7 @@ namespace ETSI.ARF.WorldStorage.UI WorldAnchor obj = GenerateObject(); WorldAnchorRequest.CreateWorldAnchorAsync(worldStorageServer, obj, (response) => { - UUID = response.result; + UUID = response.result.Message; UUID = UUID.Trim('"'); //Bugfix: remove " from server return value WorldStorageWindow.WorldStorageWindowSingleton.GetWorldAnchors(); }); diff --git a/Editor/Scripts/Windows/WorldLinkWindow.cs b/Editor/Scripts/Windows/WorldLinkWindow.cs index 147417b..0dbb9be 100644 --- a/Editor/Scripts/Windows/WorldLinkWindow.cs +++ b/Editor/Scripts/Windows/WorldLinkWindow.cs @@ -275,7 +275,7 @@ namespace ETSI.ARF.WorldStorage.UI WorldLink obj = GenerateObject(); WorldLinkRequest.UpdateWorldLinkAsync(worldStorageServer, obj, (response) => { - UUID = response.result; + UUID = response.result.Message; UUID = UUID.Trim('"'); //Bugfix: remove " from server return value if (WorldStorageWindow.WorldStorageWindowSingleton != null) @@ -469,7 +469,7 @@ namespace ETSI.ARF.WorldStorage.UI WorldLink obj = GenerateObject(); WorldLinkRequest.CreateWorldLinkAsync(worldStorageServer, obj, (response) => { - UUID = response.result; + UUID = response.result.Message; UUID = UUID.Trim('"'); //Bugfix: remove " from server return value WorldStorageWindow.WorldStorageWindowSingleton.GetWorldLinks(); }); diff --git a/Editor/Scripts/Windows/WorldStorageWindow.cs b/Editor/Scripts/Windows/WorldStorageWindow.cs index d8d036e..2230159 100644 --- a/Editor/Scripts/Windows/WorldStorageWindow.cs +++ b/Editor/Scripts/Windows/WorldStorageWindow.cs @@ -545,14 +545,16 @@ namespace ETSI.ARF.WorldStorage.UI return text.Split('[', ']')[1]; } } + public void GetCreators() { // Get all objects Debug.Log("Get all creators id"); TrackableRequest.GetTrackablesAsync(worldStorageServer, (response) => { + // Workaround creators.Clear(); - foreach (var item in response.result) + foreach (var item in response.result.Trackables) { if (!creators.Contains(item.CreatorUUID.ToString())) creators.Add(item.CreatorUUID.ToString()); } @@ -585,8 +587,8 @@ namespace ETSI.ARF.WorldStorage.UI repaint = true; TrackableRequest.GetTrackablesAsync(worldStorageServer, (response) => { - Debug.Log("Get objects num = " + response.result.Count); - foreach (var item in response.result) + Debug.Log("Get objects num = " + response.result.Trackables.Count); + foreach (var item in response.result.Trackables) { if (filterByKeyValueTag != "") { @@ -608,7 +610,8 @@ namespace ETSI.ARF.WorldStorage.UI repaint = true; WorldAnchorRequest.GetWorldAnchorsAsync(worldStorageServer, (response) => { - foreach (var item in response.result) + Debug.Log("Get objects num = " + response.result.WorldAnchors.Count); + foreach (var item in response.result.WorldAnchors) { if (filterByKeyValueTag != "") { @@ -630,7 +633,8 @@ namespace ETSI.ARF.WorldStorage.UI repaint = true; WorldLinkRequest.GetWorldLinksAsync(worldStorageServer, (response) => { - foreach (var item in response.result) + Debug.Log("Get objects num = " + response.result.WorldLinks.Count); + foreach (var item in response.result.WorldLinks) { links.Add(item.UUID.ToString()); } diff --git a/Runtime/Scenes/OpenAPITest.cs b/Runtime/Scenes/OpenAPITest.cs index b3fa21c..e4298c6 100644 --- a/Runtime/Scenes/OpenAPITest.cs +++ b/Runtime/Scenes/OpenAPITest.cs @@ -119,7 +119,7 @@ public class OpenAPITest : MonoBehaviour return; } - ResponseObject> token = TrackableRequest.GetTrackablesAsync(server, (response) => + ResponseObject token = TrackableRequest.GetTrackablesAsync(server, (response) => { handleResponseQ.Enqueue(response); }); @@ -136,9 +136,9 @@ public class OpenAPITest : MonoBehaviour Trackable tr = new Trackable(DateTime.Now.ToFileTime().ToString()); tr.TrackableType = TrackableType.OTHER; - ResponseObject token = TrackableRequest.CreateTrackableAsync(server, tr, (response) => + ResponseObject token = TrackableRequest.CreateTrackableAsync(server, tr, (response) => { - lastUUID = Guid.Parse(response.result); + lastUUID = Guid.Parse(response.result.Message); handleResponseQ.Enqueue(response); }); lastUUID = Guid.Empty; @@ -161,9 +161,9 @@ public class OpenAPITest : MonoBehaviour ResponseObject token = TrackableRequest.GetTrackableAsync(server, lastUUID, (response) => { response.result.Name += "'"; - ResponseObject token = TrackableRequest.UpdateTrackableAsync(server, response.result, (response) => + ResponseObject token = TrackableRequest.UpdateTrackableAsync(server, response.result, (response) => { - handleResponseQ.Enqueue(response); + handleResponseQ.Enqueue(response.result.Message); }); }); } @@ -182,9 +182,9 @@ public class OpenAPITest : MonoBehaviour return; } - ResponseObject token = TrackableRequest.DeleteTrackableAsync(server, lastUUID, (response) => + ResponseObject token = TrackableRequest.DeleteTrackableAsync(server, lastUUID, (response) => { - handleResponseQ.Enqueue(response); + handleResponseQ.Enqueue(response.result.Message); lastUUID = Guid.Empty; }); } diff --git a/Runtime/Scripts/GraphEditor/WorldStorageRequest.cs b/Runtime/Scripts/GraphEditor/WorldStorageRequest.cs index a770667..4b6999f 100644 --- a/Runtime/Scripts/GraphEditor/WorldStorageRequest.cs +++ b/Runtime/Scripts/GraphEditor/WorldStorageRequest.cs @@ -124,17 +124,17 @@ namespace ETSI.ARF.WorldStorage //public Task GetNumOfAssets() => apiClient.NumOfAssetsAsync(); //public bool IsAssetExists(Guid id) => apiClient.IsAssetId(id); - public ResponseObject AddTrackableAsync(Action> func, Trackable trackable) + public ResponseObject AddTrackableAsync(Action> func, Trackable trackable) { return TrackableRequest.CreateTrackableAsync(wsServer, trackable, func); } - public ResponseObject DeleteTrackableAsync(Action> func, Guid id) + public ResponseObject DeleteTrackableAsync(Action> func, Guid id) { return TrackableRequest.DeleteTrackableAsync(wsServer, id, func); } - public ResponseObject ModifyTrackableAsync(Action> func, Trackable trackable) + public ResponseObject ModifyTrackableAsync(Action> func, Trackable trackable) { return TrackableRequest.UpdateTrackableAsync(wsServer, trackable, func); } @@ -144,7 +144,7 @@ namespace ETSI.ARF.WorldStorage return TrackableRequest.GetTrackableAsync(wsServer, id, func); } - public ResponseObject> GetTrackableListAsync(Action>> func, int? max = 1) + public ResponseObject GetTrackableListAsync(Action> func, int? max = 1) { return TrackableRequest.GetTrackablesAsync(wsServer, func); } diff --git a/Runtime/Scripts/OpenAPI/Generated/WorldStorageOpenAPI.cs b/Runtime/Scripts/OpenAPI/Generated/WorldStorageOpenAPI.cs index ba07b09..df77043 100644 --- a/Runtime/Scripts/OpenAPI/Generated/WorldStorageOpenAPI.cs +++ b/Runtime/Scripts/OpenAPI/Generated/WorldStorageOpenAPI.cs @@ -1,6 +1,6 @@ //---------------------- // -// Generated using the NSwag toolchain v14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// Generated using the NSwag toolchain v14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) // //---------------------- @@ -8,6 +8,7 @@ #pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." #pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' #pragma warning disable 612 // Disable "CS0612 '...' is obsolete" +#pragma warning disable 649 // Disable "CS0649 Field is never assigned to, and will always have its default value null" #pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... #pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." #pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" @@ -15,23 +16,25 @@ #pragma warning disable 8603 // Disable "CS8603 Possible null reference return" #pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter" #pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type" -#pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes). +#pragma warning disable 8765 // Disable "CS8765 Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes)." namespace ETSI.ARF.OpenAPI.WorldStorage { using System = global::System; - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class WorldStorageClient { private ETSI.ARF.OpenAPI.WorldStorage.IHttpClient _httpClient; private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true); + private Newtonsoft.Json.JsonSerializerSettings _instanceSettings; #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. public WorldStorageClient(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient httpClient) #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. { _httpClient = httpClient; + Initialize(); } private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() @@ -41,10 +44,12 @@ namespace ETSI.ARF.OpenAPI.WorldStorage return settings; } - protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } } + protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _instanceSettings ?? _settings.Value; } } static partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); + partial void Initialize(); + partial void PrepareRequest(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient client, System.Net.Http.HttpRequestMessage request, string url); partial void PrepareRequest(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); partial void ProcessResponse(ETSI.ARF.OpenAPI.WorldStorage.IHttpClient client, System.Net.Http.HttpResponseMessage response); @@ -329,7 +334,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// the list of all trackables and his encoding structure associated representing the supported data of the User /// Successful operation. /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetRelocalizationInformationAsync(string token, System.Collections.Generic.IEnumerable uuids, System.Collections.Generic.IEnumerable capabilities) + public virtual System.Threading.Tasks.Task GetRelocalizationInformationAsync(string token, System.Collections.Generic.IEnumerable uuids, System.Collections.Generic.IEnumerable capabilities) { return GetRelocalizationInformationAsync(token, uuids, capabilities, System.Threading.CancellationToken.None); } @@ -341,7 +346,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// the list of all trackables and his encoding structure associated representing the supported data of the User /// Successful operation. /// A server side error occurred. - public virtual Response GetRelocalizationInformation(string token, System.Collections.Generic.IEnumerable uuids, System.Collections.Generic.IEnumerable capabilities) + public virtual RelocalizationInformations GetRelocalizationInformation(string token, System.Collections.Generic.IEnumerable uuids, System.Collections.Generic.IEnumerable capabilities) { return System.Threading.Tasks.Task.Run(async () => await GetRelocalizationInformationAsync(token, uuids, capabilities, System.Threading.CancellationToken.None)).GetAwaiter().GetResult(); } @@ -354,7 +359,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// the list of all trackables and his encoding structure associated representing the supported data of the User /// Successful operation. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetRelocalizationInformationAsync(string token, System.Collections.Generic.IEnumerable uuids, System.Collections.Generic.IEnumerable capabilities, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetRelocalizationInformationAsync(string token, System.Collections.Generic.IEnumerable uuids, System.Collections.Generic.IEnumerable capabilities, System.Threading.CancellationToken cancellationToken) { if (uuids == null) throw new System.ArgumentNullException("uuids"); @@ -408,7 +413,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -418,16 +423,32 @@ namespace ETSI.ARF.OpenAPI.WorldStorage else if (status_ == 400) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Invalid UUID supplied.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Invalid UUID supplied.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 404) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Not found, could not find UUID in database.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Not found, could not find UUID in database.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 511) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("The secret token is not valid. Please ask an ISG ARF team member for a valid token.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -462,7 +483,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// The Trackable to be added to the world storage. /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual System.Threading.Tasks.Task AddTrackableAsync(string token, Trackable body) + public virtual System.Threading.Tasks.Task AddTrackableAsync(string token, Trackable body) { return AddTrackableAsync(token, body, System.Threading.CancellationToken.None); } @@ -476,7 +497,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// The Trackable to be added to the world storage. /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual string AddTrackable(string token, Trackable body) + public virtual Success AddTrackable(string token, Trackable body) { return System.Threading.Tasks.Task.Run(async () => await AddTrackableAsync(token, body, System.Threading.CancellationToken.None)).GetAwaiter().GetResult(); } @@ -491,7 +512,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// The Trackable to be added to the world storage. /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task AddTrackableAsync(string token, Trackable body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task AddTrackableAsync(string token, Trackable body, System.Threading.CancellationToken cancellationToken) { if (body == null) throw new System.ArgumentNullException("body"); @@ -505,12 +526,12 @@ namespace ETSI.ARF.OpenAPI.WorldStorage if (token != null) request_.Headers.TryAddWithoutValidation("token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value); + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); var content_ = new System.Net.Http.StringContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; request_.Method = new System.Net.Http.HttpMethod("POST"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); @@ -542,30 +563,42 @@ namespace ETSI.ARF.OpenAPI.WorldStorage var status_ = (int)response_.StatusCode; if (status_ == 200) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - return result_; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else - if (status_ == 201) + if (status_ == 400) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - return result_; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Bad request.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else - if (status_ == 400) + if (status_ == 409) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Bad request.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Invalid UUID, id must be a Nil value.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else - if (status_ == 409) + if (status_ == 511) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Invalid UUID, id must be a Nil value.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("The secret token is not valid. Please ask an ISG ARF team member for a valid token.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -598,9 +631,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Modify an existing Trackable given a json object containing all the required information. <br> **Please note that ID of the object is required in the JSON** /// /// The Trackable to be modified in the world storage. - /// OK, return the UUID of the modified Trackable. + /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual System.Threading.Tasks.Task ModifyTrackableAsync(string token, Trackable body) + public virtual System.Threading.Tasks.Task ModifyTrackableAsync(string token, Trackable body) { return ModifyTrackableAsync(token, body, System.Threading.CancellationToken.None); } @@ -612,9 +645,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Modify an existing Trackable given a json object containing all the required information. <br> **Please note that ID of the object is required in the JSON** /// /// The Trackable to be modified in the world storage. - /// OK, return the UUID of the modified Trackable. + /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual string ModifyTrackable(string token, Trackable body) + public virtual Success ModifyTrackable(string token, Trackable body) { return System.Threading.Tasks.Task.Run(async () => await ModifyTrackableAsync(token, body, System.Threading.CancellationToken.None)).GetAwaiter().GetResult(); } @@ -627,9 +660,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Modify an existing Trackable given a json object containing all the required information. <br> **Please note that ID of the object is required in the JSON** /// /// The Trackable to be modified in the world storage. - /// OK, return the UUID of the modified Trackable. + /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ModifyTrackableAsync(string token, Trackable body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ModifyTrackableAsync(string token, Trackable body, System.Threading.CancellationToken cancellationToken) { if (body == null) throw new System.ArgumentNullException("body"); @@ -643,12 +676,12 @@ namespace ETSI.ARF.OpenAPI.WorldStorage if (token != null) request_.Headers.TryAddWithoutValidation("token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value); + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); var content_ = new System.Net.Http.StringContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; request_.Method = new System.Net.Http.HttpMethod("PUT"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); @@ -680,23 +713,42 @@ namespace ETSI.ARF.OpenAPI.WorldStorage var status_ = (int)response_.StatusCode; if (status_ == 200) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - return result_; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else if (status_ == 400) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Bad request.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Bad request.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 404) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Not found, could not find UUID in database.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Not found, could not find UUID in database.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 511) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("The secret token is not valid. Please ask an ISG ARF team member for a valid token.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -730,7 +782,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// OK, return all the Trackables defined by the world storage. /// A server side error occurred. - public virtual System.Threading.Tasks.Task> GetTrackablesAsync(string token) + public virtual System.Threading.Tasks.Task GetTrackablesAsync(string token) { return GetTrackablesAsync(token, System.Threading.CancellationToken.None); } @@ -743,7 +795,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// OK, return all the Trackables defined by the world storage. /// A server side error occurred. - public virtual System.Collections.Generic.List GetTrackables(string token) + public virtual TrackablesResponse GetTrackables(string token) { return System.Threading.Tasks.Task.Run(async () => await GetTrackablesAsync(token, System.Threading.CancellationToken.None)).GetAwaiter().GetResult(); } @@ -757,7 +809,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// OK, return all the Trackables defined by the world storage. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task> GetTrackablesAsync(string token, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetTrackablesAsync(string token, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -801,7 +853,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -809,11 +861,24 @@ namespace ETSI.ARF.OpenAPI.WorldStorage return objectResponse_.Object; } else - if (status_ == 201) + if (status_ == 401) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Null response.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Null response.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 511) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("The secret token is not valid. Please ask an ISG ARF team member for a valid token.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -935,16 +1000,42 @@ namespace ETSI.ARF.OpenAPI.WorldStorage else if (status_ == 400) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Invalid UUID supplied.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Invalid UUID supplied.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Null response.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 404) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Not found, could not find UUID in database.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Not found, could not find UUID in database.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 511) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("The secret token is not valid. Please ask an ISG ARF team member for a valid token.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -973,9 +1064,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Delete a single Trackable stored in the world storage from its ID. /// /// Trackable UUID to delete. - /// OK, delete successful. + /// Success request. /// A server side error occurred. - public virtual System.Threading.Tasks.Task DeleteTrackableAsync(string token, System.Guid trackableUUID) + public virtual System.Threading.Tasks.Task DeleteTrackableAsync(string token, System.Guid trackableUUID) { return DeleteTrackableAsync(token, trackableUUID, System.Threading.CancellationToken.None); } @@ -987,9 +1078,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Delete a single Trackable stored in the world storage from its ID. /// /// Trackable UUID to delete. - /// OK, delete successful. + /// Success request. /// A server side error occurred. - public virtual string DeleteTrackable(string token, System.Guid trackableUUID) + public virtual Success DeleteTrackable(string token, System.Guid trackableUUID) { return System.Threading.Tasks.Task.Run(async () => await DeleteTrackableAsync(token, trackableUUID, System.Threading.CancellationToken.None)).GetAwaiter().GetResult(); } @@ -1002,9 +1093,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Delete a single Trackable stored in the world storage from its ID. /// /// Trackable UUID to delete. - /// OK, delete successful. + /// Success request. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task DeleteTrackableAsync(string token, System.Guid trackableUUID, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task DeleteTrackableAsync(string token, System.Guid trackableUUID, System.Threading.CancellationToken cancellationToken) { if (trackableUUID == null) throw new System.ArgumentNullException("trackableUUID"); @@ -1019,7 +1110,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage if (token != null) request_.Headers.TryAddWithoutValidation("token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); request_.Method = new System.Net.Http.HttpMethod("DELETE"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); @@ -1052,23 +1143,42 @@ namespace ETSI.ARF.OpenAPI.WorldStorage var status_ = (int)response_.StatusCode; if (status_ == 200) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - return result_; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else if (status_ == 400) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Invalid UUID supplied.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Invalid UUID supplied.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 404) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Not found, could not find UUID in database.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Not found, could not find UUID in database.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 511) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("The secret token is not valid. Please ask an ISG ARF team member for a valid token.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -1097,9 +1207,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Create a new World Anchor from a json object containing all the required information and add it to the world storage. <br>As a result you will get the ID of the newly created World Anchor. /// /// The World Anchor to be added to the world storage. - /// OK, return the UUID of the World Anchor defined by the world storage. + /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual System.Threading.Tasks.Task AddWorldAnchorAsync(string token, WorldAnchor body) + public virtual System.Threading.Tasks.Task AddWorldAnchorAsync(string token, WorldAnchor body) { return AddWorldAnchorAsync(token, body, System.Threading.CancellationToken.None); } @@ -1111,9 +1221,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Create a new World Anchor from a json object containing all the required information and add it to the world storage. <br>As a result you will get the ID of the newly created World Anchor. /// /// The World Anchor to be added to the world storage. - /// OK, return the UUID of the World Anchor defined by the world storage. + /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual string AddWorldAnchor(string token, WorldAnchor body) + public virtual Success AddWorldAnchor(string token, WorldAnchor body) { return System.Threading.Tasks.Task.Run(async () => await AddWorldAnchorAsync(token, body, System.Threading.CancellationToken.None)).GetAwaiter().GetResult(); } @@ -1126,9 +1236,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Create a new World Anchor from a json object containing all the required information and add it to the world storage. <br>As a result you will get the ID of the newly created World Anchor. /// /// The World Anchor to be added to the world storage. - /// OK, return the UUID of the World Anchor defined by the world storage. + /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task AddWorldAnchorAsync(string token, WorldAnchor body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task AddWorldAnchorAsync(string token, WorldAnchor body, System.Threading.CancellationToken cancellationToken) { if (body == null) throw new System.ArgumentNullException("body"); @@ -1142,12 +1252,12 @@ namespace ETSI.ARF.OpenAPI.WorldStorage if (token != null) request_.Headers.TryAddWithoutValidation("token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value); + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); var content_ = new System.Net.Http.StringContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; request_.Method = new System.Net.Http.HttpMethod("POST"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); @@ -1179,30 +1289,42 @@ namespace ETSI.ARF.OpenAPI.WorldStorage var status_ = (int)response_.StatusCode; if (status_ == 200) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - return result_; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else - if (status_ == 201) + if (status_ == 400) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - return result_; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Bad request.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else - if (status_ == 400) + if (status_ == 409) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Bad request.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Invalid UUID, id must be a Nil value.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else - if (status_ == 409) + if (status_ == 511) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Invalid UUID, id must be a Nil value.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("The secret token is not valid. Please ask an ISG ARF team member for a valid token.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -1235,9 +1357,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Modify an existing World Anchor given a json object containing all the required information. <br> **Please note that ID of the object is required in the JSON** /// /// The World Anchor to be modified in the world storage. - /// OK, return the UUID of the modified World Anchor. + /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual System.Threading.Tasks.Task ModifyWorldAnchorAsync(string token, WorldAnchor body) + public virtual System.Threading.Tasks.Task ModifyWorldAnchorAsync(string token, WorldAnchor body) { return ModifyWorldAnchorAsync(token, body, System.Threading.CancellationToken.None); } @@ -1249,9 +1371,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Modify an existing World Anchor given a json object containing all the required information. <br> **Please note that ID of the object is required in the JSON** /// /// The World Anchor to be modified in the world storage. - /// OK, return the UUID of the modified World Anchor. + /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual string ModifyWorldAnchor(string token, WorldAnchor body) + public virtual Success ModifyWorldAnchor(string token, WorldAnchor body) { return System.Threading.Tasks.Task.Run(async () => await ModifyWorldAnchorAsync(token, body, System.Threading.CancellationToken.None)).GetAwaiter().GetResult(); } @@ -1264,9 +1386,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Modify an existing World Anchor given a json object containing all the required information. <br> **Please note that ID of the object is required in the JSON** /// /// The World Anchor to be modified in the world storage. - /// OK, return the UUID of the modified World Anchor. + /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ModifyWorldAnchorAsync(string token, WorldAnchor body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ModifyWorldAnchorAsync(string token, WorldAnchor body, System.Threading.CancellationToken cancellationToken) { if (body == null) throw new System.ArgumentNullException("body"); @@ -1280,12 +1402,12 @@ namespace ETSI.ARF.OpenAPI.WorldStorage if (token != null) request_.Headers.TryAddWithoutValidation("token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value); + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); var content_ = new System.Net.Http.StringContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; request_.Method = new System.Net.Http.HttpMethod("PUT"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); @@ -1317,23 +1439,42 @@ namespace ETSI.ARF.OpenAPI.WorldStorage var status_ = (int)response_.StatusCode; if (status_ == 200) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - return result_; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else if (status_ == 400) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Bad request.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Bad request.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 404) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Not found, could not find UUID in database.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Not found, could not find UUID in database.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 511) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("The secret token is not valid. Please ask an ISG ARF team member for a valid token.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -1367,7 +1508,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// OK, return all the World Anchors defined by the world storage. /// A server side error occurred. - public virtual System.Threading.Tasks.Task> GetWorldAnchorsAsync(string token) + public virtual System.Threading.Tasks.Task GetWorldAnchorsAsync(string token) { return GetWorldAnchorsAsync(token, System.Threading.CancellationToken.None); } @@ -1380,7 +1521,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// OK, return all the World Anchors defined by the world storage. /// A server side error occurred. - public virtual System.Collections.Generic.List GetWorldAnchors(string token) + public virtual WorldAnchorsResponse GetWorldAnchors(string token) { return System.Threading.Tasks.Task.Run(async () => await GetWorldAnchorsAsync(token, System.Threading.CancellationToken.None)).GetAwaiter().GetResult(); } @@ -1394,7 +1535,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// OK, return all the World Anchors defined by the world storage. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task> GetWorldAnchorsAsync(string token, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetWorldAnchorsAsync(string token, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -1438,7 +1579,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -1446,24 +1587,37 @@ namespace ETSI.ARF.OpenAPI.WorldStorage return objectResponse_.Object; } else - if (status_ == 201) + if (status_ == 401) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Null response.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Null response.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else + if (status_ == 511) { var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } - throw new ApiException("Unexpected error.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + throw new ApiException("The secret token is not valid. Please ask an ISG ARF team member for a valid token.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } - } - finally - { + else + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Unexpected error.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + } + finally + { if (disposeResponse_) response_.Dispose(); } @@ -1572,16 +1726,42 @@ namespace ETSI.ARF.OpenAPI.WorldStorage else if (status_ == 400) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Invalid UUID supplied.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Invalid UUID supplied.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Null response.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 404) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Not found, could not find UUID in database.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Not found, could not find UUID in database.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 511) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("The secret token is not valid. Please ask an ISG ARF team member for a valid token.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -1610,9 +1790,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Delete a single World Anchor stored in the world storage from its ID. /// /// World Anchor UUID to delete. - /// OK, delete successful. + /// Success request. /// A server side error occurred. - public virtual System.Threading.Tasks.Task DeleteWorldAnchorAsync(string token, System.Guid worldAnchorUUID) + public virtual System.Threading.Tasks.Task DeleteWorldAnchorAsync(string token, System.Guid worldAnchorUUID) { return DeleteWorldAnchorAsync(token, worldAnchorUUID, System.Threading.CancellationToken.None); } @@ -1624,9 +1804,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Delete a single World Anchor stored in the world storage from its ID. /// /// World Anchor UUID to delete. - /// OK, delete successful. + /// Success request. /// A server side error occurred. - public virtual string DeleteWorldAnchor(string token, System.Guid worldAnchorUUID) + public virtual Success DeleteWorldAnchor(string token, System.Guid worldAnchorUUID) { return System.Threading.Tasks.Task.Run(async () => await DeleteWorldAnchorAsync(token, worldAnchorUUID, System.Threading.CancellationToken.None)).GetAwaiter().GetResult(); } @@ -1639,9 +1819,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Delete a single World Anchor stored in the world storage from its ID. /// /// World Anchor UUID to delete. - /// OK, delete successful. + /// Success request. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task DeleteWorldAnchorAsync(string token, System.Guid worldAnchorUUID, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task DeleteWorldAnchorAsync(string token, System.Guid worldAnchorUUID, System.Threading.CancellationToken cancellationToken) { if (worldAnchorUUID == null) throw new System.ArgumentNullException("worldAnchorUUID"); @@ -1656,7 +1836,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage if (token != null) request_.Headers.TryAddWithoutValidation("token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); request_.Method = new System.Net.Http.HttpMethod("DELETE"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); @@ -1689,23 +1869,42 @@ namespace ETSI.ARF.OpenAPI.WorldStorage var status_ = (int)response_.StatusCode; if (status_ == 200) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - return result_; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else if (status_ == 400) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Invalid UUID supplied.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Invalid UUID supplied.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 404) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Not found, could not find UUID in database.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Not found, could not find UUID in database.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 511) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("The secret token is not valid. Please ask an ISG ARF team member for a valid token.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -1734,9 +1933,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Create a new World Link from a json object containing all the required information and add it to the world storage. <br>As a result you will get the ID of the newly created World Link. /// /// The link to be added to the world storage. - /// OK, return the UUID of the World Link defined by the world storage. + /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual System.Threading.Tasks.Task AddWorldLinkAsync(string token, WorldLink body) + public virtual System.Threading.Tasks.Task AddWorldLinkAsync(string token, WorldLink body) { return AddWorldLinkAsync(token, body, System.Threading.CancellationToken.None); } @@ -1748,9 +1947,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Create a new World Link from a json object containing all the required information and add it to the world storage. <br>As a result you will get the ID of the newly created World Link. /// /// The link to be added to the world storage. - /// OK, return the UUID of the World Link defined by the world storage. + /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual string AddWorldLink(string token, WorldLink body) + public virtual Success AddWorldLink(string token, WorldLink body) { return System.Threading.Tasks.Task.Run(async () => await AddWorldLinkAsync(token, body, System.Threading.CancellationToken.None)).GetAwaiter().GetResult(); } @@ -1763,9 +1962,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Create a new World Link from a json object containing all the required information and add it to the world storage. <br>As a result you will get the ID of the newly created World Link. /// /// The link to be added to the world storage. - /// OK, return the UUID of the World Link defined by the world storage. + /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task AddWorldLinkAsync(string token, WorldLink body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task AddWorldLinkAsync(string token, WorldLink body, System.Threading.CancellationToken cancellationToken) { if (body == null) throw new System.ArgumentNullException("body"); @@ -1779,12 +1978,12 @@ namespace ETSI.ARF.OpenAPI.WorldStorage if (token != null) request_.Headers.TryAddWithoutValidation("token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value); + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); var content_ = new System.Net.Http.StringContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; request_.Method = new System.Net.Http.HttpMethod("POST"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); @@ -1816,30 +2015,42 @@ namespace ETSI.ARF.OpenAPI.WorldStorage var status_ = (int)response_.StatusCode; if (status_ == 200) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - return result_; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else - if (status_ == 201) + if (status_ == 400) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - return result_; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Bad request.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else - if (status_ == 400) + if (status_ == 409) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Bad request.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Invalid UUID, id must be a Nil value.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else - if (status_ == 409) + if (status_ == 511) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Invalid UUID, id must be a Nil value.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("The secret token is not valid. Please ask an ISG ARF team member for a valid token.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -1872,9 +2083,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Modify an existing World Link given a json object containing all the required information. <br> **Please note that ID of the object is required in the JSON** /// /// The World Link to be modified in the world storage. - /// OK, return the UUID of the modified World Link. + /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual System.Threading.Tasks.Task ModifyWorldLinkAsync(string token, WorldLink body) + public virtual System.Threading.Tasks.Task ModifyWorldLinkAsync(string token, WorldLink body) { return ModifyWorldLinkAsync(token, body, System.Threading.CancellationToken.None); } @@ -1886,9 +2097,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Modify an existing World Link given a json object containing all the required information. <br> **Please note that ID of the object is required in the JSON** /// /// The World Link to be modified in the world storage. - /// OK, return the UUID of the modified World Link. + /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual string ModifyWorldLink(string token, WorldLink body) + public virtual Success ModifyWorldLink(string token, WorldLink body) { return System.Threading.Tasks.Task.Run(async () => await ModifyWorldLinkAsync(token, body, System.Threading.CancellationToken.None)).GetAwaiter().GetResult(); } @@ -1901,9 +2112,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Modify an existing World Link given a json object containing all the required information. <br> **Please note that ID of the object is required in the JSON** /// /// The World Link to be modified in the world storage. - /// OK, return the UUID of the modified World Link. + /// OK, return the UUID of the Trackable defined by the world storage. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ModifyWorldLinkAsync(string token, WorldLink body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ModifyWorldLinkAsync(string token, WorldLink body, System.Threading.CancellationToken cancellationToken) { if (body == null) throw new System.ArgumentNullException("body"); @@ -1917,12 +2128,12 @@ namespace ETSI.ARF.OpenAPI.WorldStorage if (token != null) request_.Headers.TryAddWithoutValidation("token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value); + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); var content_ = new System.Net.Http.StringContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; request_.Method = new System.Net.Http.HttpMethod("PUT"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); @@ -1954,23 +2165,42 @@ namespace ETSI.ARF.OpenAPI.WorldStorage var status_ = (int)response_.StatusCode; if (status_ == 200) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - return result_; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else if (status_ == 400) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Bad request.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Bad request.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 404) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Not found, could not find UUID in database.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Not found, could not find UUID in database.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 511) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("The secret token is not valid. Please ask an ISG ARF team member for a valid token.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -2004,7 +2234,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// OK return all the World Links defined by the world storage. /// A server side error occurred. - public virtual System.Threading.Tasks.Task> GetWorldLinksAsync(string token) + public virtual System.Threading.Tasks.Task GetWorldLinksAsync(string token) { return GetWorldLinksAsync(token, System.Threading.CancellationToken.None); } @@ -2017,7 +2247,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// OK return all the World Links defined by the world storage. /// A server side error occurred. - public virtual System.Collections.Generic.List GetWorldLinks(string token) + public virtual WorldLinksResponse GetWorldLinks(string token) { return System.Threading.Tasks.Task.Run(async () => await GetWorldLinksAsync(token, System.Threading.CancellationToken.None)).GetAwaiter().GetResult(); } @@ -2031,7 +2261,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// OK return all the World Links defined by the world storage. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task> GetWorldLinksAsync(string token, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetWorldLinksAsync(string token, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -2075,7 +2305,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -2083,11 +2313,24 @@ namespace ETSI.ARF.OpenAPI.WorldStorage return objectResponse_.Object; } else - if (status_ == 201) + if (status_ == 401) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Null response.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Null response.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 511) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("The secret token is not valid. Please ask an ISG ARF team member for a valid token.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -2209,16 +2452,42 @@ namespace ETSI.ARF.OpenAPI.WorldStorage else if (status_ == 400) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Invalid UUID supplied.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Invalid UUID supplied.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Null response.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 404) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Not found, could not find UUID in database.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Not found, could not find UUID in database.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 511) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("The secret token is not valid. Please ask an ISG ARF team member for a valid token.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -2247,9 +2516,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Delete a single World Link stored in the world storage from its ID. /// /// World Link id to delete. - /// OK, delete successful. + /// Success request. /// A server side error occurred. - public virtual System.Threading.Tasks.Task DeleteWorldLinkAsync(string token, System.Guid worldLinkUUID) + public virtual System.Threading.Tasks.Task DeleteWorldLinkAsync(string token, System.Guid worldLinkUUID) { return DeleteWorldLinkAsync(token, worldLinkUUID, System.Threading.CancellationToken.None); } @@ -2261,9 +2530,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Delete a single World Link stored in the world storage from its ID. /// /// World Link id to delete. - /// OK, delete successful. + /// Success request. /// A server side error occurred. - public virtual string DeleteWorldLink(string token, System.Guid worldLinkUUID) + public virtual Success DeleteWorldLink(string token, System.Guid worldLinkUUID) { return System.Threading.Tasks.Task.Run(async () => await DeleteWorldLinkAsync(token, worldLinkUUID, System.Threading.CancellationToken.None)).GetAwaiter().GetResult(); } @@ -2276,9 +2545,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// Delete a single World Link stored in the world storage from its ID. /// /// World Link id to delete. - /// OK, delete successful. + /// Success request. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task DeleteWorldLinkAsync(string token, System.Guid worldLinkUUID, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task DeleteWorldLinkAsync(string token, System.Guid worldLinkUUID, System.Threading.CancellationToken cancellationToken) { if (worldLinkUUID == null) throw new System.ArgumentNullException("worldLinkUUID"); @@ -2293,7 +2562,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage if (token != null) request_.Headers.TryAddWithoutValidation("token", ConvertToString(token, System.Globalization.CultureInfo.InvariantCulture)); request_.Method = new System.Net.Http.HttpMethod("DELETE"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); @@ -2326,23 +2595,32 @@ namespace ETSI.ARF.OpenAPI.WorldStorage var status_ = (int)response_.StatusCode; if (status_ == 200) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - return result_; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else if (status_ == 400) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Invalid UUID supplied.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Invalid UUID supplied.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 404) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - throw new ApiException("Not found, could not find UUID in database.", status_, responseData_, headers_, result_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Not found, could not find UUID in database.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -2479,7 +2757,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// An element representing all information needed in relation with a Trackable or a WorldAnchor. /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class RelocalizationInformation { /// @@ -2512,7 +2790,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// An element representing a Trackable object in the real world. /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Trackable { /// @@ -2576,7 +2854,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// An element describing a pose in the world graph. /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class WorldAnchor { /// @@ -2624,7 +2902,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// An object holding the info of a transform between two elements. /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class WorldLink { /// @@ -2683,7 +2961,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// List of additional parameters to be stored with the object. /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class KeyvalueTagList : System.Collections.Generic.Dictionary> { @@ -2692,7 +2970,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// An object representing a supported capability of the World Analysis and its associated metadata /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Capability { [Newtonsoft.Json.JsonProperty("trackableType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] @@ -2734,7 +3012,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// An object holding the info of a Trackable`'`s encoding information `:` the data format and the version. /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class EncodingInformationStructure { /// @@ -2761,13 +3039,10 @@ namespace ETSI.ARF.OpenAPI.WorldStorage } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Error { - [Newtonsoft.Json.JsonProperty("code", Required = Newtonsoft.Json.Required.Always)] - public int Code { get; set; } - - [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Message { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -2784,7 +3059,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// Mode representing the context of the relocalization information (AR device to WorldAnchor/Trackable or WorldAnchor/Trackable to AR device) /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public enum Mode_WorldStorage { @@ -2799,16 +3074,33 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// Size object in format {width, length, depth}. /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Size : System.Collections.ObjectModel.Collection { } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Success + { + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Message { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + /// /// Type for trackable /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public enum TrackableType { @@ -2835,7 +3127,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// Coordinate reference system of the world anchor, a 4*4 matrix (rowmajor) represented by a float vector. /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Transform3D : System.Collections.ObjectModel.Collection { @@ -2844,7 +3136,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// Trackable or Anchor /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public enum TypeWorldStorage { @@ -2862,7 +3154,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// Unit of length. /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public enum UnitSystem { @@ -2901,8 +3193,8 @@ namespace ETSI.ARF.OpenAPI.WorldStorage } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Anonymous + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class UuidAndMode { [Newtonsoft.Json.JsonProperty("uuid", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public System.Guid Uuid { get; set; } @@ -2922,8 +3214,8 @@ namespace ETSI.ARF.OpenAPI.WorldStorage } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class RelocalizationInformations { [Newtonsoft.Json.JsonProperty("RelocInfo", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public System.Collections.Generic.ICollection RelocInfo { get; set; } @@ -2939,7 +3231,58 @@ namespace ETSI.ARF.OpenAPI.WorldStorage } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class TrackablesResponse + { + [Newtonsoft.Json.JsonProperty("trackables", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Trackables { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class WorldAnchorsResponse + { + [Newtonsoft.Json.JsonProperty("worldAnchors", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection WorldAnchors { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class WorldLinksResponse + { + [Newtonsoft.Json.JsonProperty("worldLinks", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection WorldLinks { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class RelocObjects { [Newtonsoft.Json.JsonProperty("trackable", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] @@ -2963,7 +3306,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public enum EncodingInformationStructureDataFormat { @@ -2989,7 +3332,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ApiException : System.Exception { public int StatusCode { get; private set; } @@ -3012,7 +3355,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage } } - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ApiException : ApiException { public TResult Result { get; private set; } diff --git a/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs b/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs index a119a03..43fd7f0 100644 --- a/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs +++ b/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// Last change: June 2024 +// Last change: September 2024 // // Depends on UniTask to support cancellation token and GetAwaiter: https://github.com/Cysharp/UniTask @@ -55,10 +55,10 @@ namespace ETSI.ARF.OpenAPI.WorldStorage public BasicHTTPClient(string baseUri) { BaseAddress = new Uri(baseUri); - _httpClient.BaseAddress = BaseAddress; + _httpClient.BaseAddress = BaseAddress; } - public BasicHTTPClient (Uri baseUri) + public BasicHTTPClient(Uri baseUri) { BaseAddress = baseUri; _httpClient.BaseAddress = BaseAddress; @@ -71,10 +71,10 @@ namespace ETSI.ARF.OpenAPI.WorldStorage public async Task SendAsync(HttpRequestMessage message, HttpCompletionOption option, CancellationToken token) { - return await _httpClient.SendAsync(message, option, token); + return await _httpClient.SendAsync(message, option, token); } - public void Dispose() + public void Dispose() { _httpClient.Dispose(); DefaultRequestHeaders.Clear(); @@ -101,6 +101,21 @@ namespace ETSI.ARF.OpenAPI.WorldStorage private readonly HttpClient _httpClient = new HttpClient(); + private void AppendARFHeaders(HttpRequestMessage message, UnityWebRequest webRequest) + { + // Add some ARF headers + foreach (var item in message.Headers) + { + try + { + List li = item.Value as List; + if (item.Key == "token") webRequest.SetRequestHeader(item.Key, li[0].ToString()); // add it + if (item.Key == "sessionID") webRequest.SetRequestHeader(item.Key, li[0].ToString()); // add it + } + catch { } // ignore it + } + } + public async Task SendAsync(HttpRequestMessage message, HttpCompletionOption option, CancellationToken token) { var content = await (message.Content?.ReadAsStringAsync() ?? Task.FromResult("")); @@ -108,6 +123,9 @@ namespace ETSI.ARF.OpenAPI.WorldStorage AppendHeaders(webRequest); + // Add the ARF API headers + AppendARFHeaders(message, webRequest); + Debug.Log("[HTTP] Request " + webRequest.uri.ToString()); try { @@ -178,6 +196,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage var (key, value) = enumerator.Current; webRequest.SetRequestHeader(key, value.First()); } + } private HttpResponseMessage CreateHttpResponseMessage(UnityWebRequest webRequest) diff --git a/Runtime/Scripts/REST/RelocalizationInformationRequest.cs b/Runtime/Scripts/REST/RelocalizationInformationRequest.cs index 5223399..1113d6a 100644 --- a/Runtime/Scripts/REST/RelocalizationInformationRequest.cs +++ b/Runtime/Scripts/REST/RelocalizationInformationRequest.cs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// Last change: May 2024 +// Last change: September 2024 // using System; using System.Collections.Generic; @@ -25,53 +25,53 @@ using Newtonsoft.Json; namespace ETSI.ARF.WorldStorage.REST { - public class RelocalizationInformationRequest : RequestBase + public class RelocalizationInformationRequest : RequestBase { - static public ResponseObject GetRelocalizationInformationAsync(WorldStorageServer ws, List uuids, List modes, List capabilities, Action> func) + static public ResponseObject GetRelocalizationInformationAsync(WorldStorageServer ws, List uuids, List modes, List capabilities, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new MyWorldStorageClient(httpClient); - ResponseObject ro = new ResponseObject("Request Reloc Information ", func); + ResponseObject ro = new ResponseObject("Request Reloc Information ", func); - List anonymous = new List(); + List anonymous = new List(); for (int i = 0; i< uuids.Count; i++) { // Check same size or give anonymous as parameter? - Anonymous newOne = new Anonymous(); + UuidAndMode newOne = new UuidAndMode(); newOne.Uuid = uuids[i]; newOne.Mode = modes[i]; anonymous.Add(newOne); } - apiClient.GetRelocalizationInformationAsync(token, anonymous, capabilities, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + apiClient.GetRelocalizationInformationAsync(token, anonymous, capabilities, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } - static public Response GetRelocalizationInformation(WorldStorageServer ws, List uuids, List modes, List capabilities) + static public RelocalizationInformations GetRelocalizationInformation(WorldStorageServer ws, List uuids, List modes, List capabilities) { return GetRelocalizationInformationSync(ws, uuids, modes, capabilities); } - static public Response GetRelocalizationInformationSync(WorldStorageServer ws, List uuids, List modes, List capabilities) + static public RelocalizationInformations GetRelocalizationInformationSync(WorldStorageServer ws, List uuids, List modes, List capabilities) { wsServer = ws; var httpClient = new BasicHTTPClient(ws.URI); apiClient = new MyWorldStorageClient(httpClient); - List anonymous = new List(); + List anonymous = new List(); for (int i = 0; i < uuids.Count; i++) { // Check same size or give anonymous as parameter? - Anonymous newOne = new Anonymous(); + UuidAndMode newOne = new UuidAndMode(); newOne.Uuid = uuids[i]; newOne.Mode = modes[i]; anonymous.Add(newOne); } - Response ro = apiClient.GetRelocalizationInformation(token, anonymous, capabilities); + RelocalizationInformations ro = apiClient.GetRelocalizationInformation(token, anonymous, capabilities); return ro; } } @@ -125,7 +125,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage /// /// /// - public override async System.Threading.Tasks.Task GetRelocalizationInformationAsync(string token, System.Collections.Generic.IEnumerable uuids, System.Collections.Generic.IEnumerable capabilities, System.Threading.CancellationToken cancellationToken) + public override async System.Threading.Tasks.Task GetRelocalizationInformationAsync(string token, System.Collections.Generic.IEnumerable uuids, System.Collections.Generic.IEnumerable capabilities, System.Threading.CancellationToken cancellationToken) { if (uuids == null) throw new System.ArgumentNullException("uuids"); @@ -178,7 +178,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); diff --git a/Runtime/Scripts/REST/RequestBase.cs b/Runtime/Scripts/REST/RequestBase.cs index 776541f..8a369f5 100644 --- a/Runtime/Scripts/REST/RequestBase.cs +++ b/Runtime/Scripts/REST/RequestBase.cs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// Last change: March 2024 +// Last change: September 2024 // using System; @@ -33,7 +33,7 @@ namespace ETSI.ARF.WorldStorage.REST static protected WorldStorageServer wsServer; static protected WorldStorageClient apiClient; - static protected string token = "ARF_Permission"; + static protected string token = "dev"; // only for development // Cache the current list static public Dictionary listOfObjects = new Dictionary(); @@ -56,7 +56,58 @@ namespace ETSI.ARF.WorldStorage.REST else Debug.Log("[REST] OpenAPI Timeout!"); } - static protected void OnReceiveListOfObjects(Task> t, object id) where TObj : IModel + static protected void OnReceiveListOfObjects(Task t, object id) // where TObj : IModel + { + if (t.IsCompleted) + { + ResponseObject o = (ResponseObject)id; + o.responseTime = DateTime.Now; + o.result = t.Result; + Debug.Log($"[REST] " + o.result.GetType()); + + // Adapation for new API, SylR + int cnt = 0; + + // Remember the new list + listOfObjects.Clear(); + + // Get the new list + if (o.result.GetType() == typeof(TrackablesResponse)) + { + Debug.Log($"[REST] TR"); + TrackablesResponse res = o.result as TrackablesResponse; + foreach (var item in res.Trackables) + { + listOfObjects.Add(item.UUID, item); + cnt++; + } + } + else if (o.GetType() == typeof(WorldAnchorsResponse)) + { + WorldAnchorsResponse res = o as WorldAnchorsResponse; + foreach (var item in res.WorldAnchors) + { + listOfObjects.Add(item.UUID, item); + cnt++; + } + } + else if (o.GetType() == typeof(WorldLinksResponse)) + { + WorldLinksResponse res = o as WorldLinksResponse; + foreach (var item in res.WorldLinks) + { + listOfObjects.Add(item.UUID, item); + cnt++; + } + } + + Debug.Log($"[REST] Server Response = Got {cnt} entrie(s) (ID={o.transactionId}, Msg={o.message})"); + o.callback?.Invoke(o); + } + else Debug.Log("[REST] OpenAPI Timeout!"); + } + + static protected void old_OnReceiveListOfObjects(Task> t, object id) where TObj : IModel { if (t.IsCompleted) { diff --git a/Runtime/Scripts/REST/TrackableRequest.cs b/Runtime/Scripts/REST/TrackableRequest.cs index 9aa9adf..ec208b3 100644 --- a/Runtime/Scripts/REST/TrackableRequest.cs +++ b/Runtime/Scripts/REST/TrackableRequest.cs @@ -60,20 +60,20 @@ namespace ETSI.ARF.WorldStorage.REST wsServer = ws; var httpClient = new BasicHTTPClient(ws.URI); apiClient = new WorldStorageClient(httpClient); - + Debug.Log("[REST] Request Trackables..."); - return apiClient.GetTrackables(token); + return apiClient.GetTrackables(token).Trackables as List; } - static public ResponseObject> GetTrackablesAsync(WorldStorageServer ws, Action>> func) + static public ResponseObject GetTrackablesAsync(WorldStorageServer ws, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); Debug.Log("[REST] Request Trackables..."); - ResponseObject> ro = new ResponseObject>("Request Trackables", func); - apiClient.GetTrackablesAsync(token, ro.cancellationToken).ContinueWith(OnReceiveListOfObjects, ro); + ResponseObject ro = new ResponseObject("Request Trackables", func); + apiClient.GetTrackablesAsync(token, ro.cancellationToken).ContinueWith(OnReceiveListOfObjects, ro); return ro; } @@ -88,10 +88,10 @@ namespace ETSI.ARF.WorldStorage.REST if (trackable.CreatorUUID == Guid.Empty) trackable.CreatorUUID = System.Guid.Parse("8fb169e2-8910-4cd5-a8f9-b7abff38d013"); Debug.Log($"[REST] Create Trackable {trackable.UUID}..."); - return apiClient.AddTrackable(token, trackable); + return apiClient.AddTrackable(token, trackable).Message; } - static public ResponseObject CreateTrackableAsync(WorldStorageServer ws, Trackable trackable, Action> func) + static public ResponseObject CreateTrackableAsync(WorldStorageServer ws, Trackable trackable, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); @@ -103,8 +103,8 @@ namespace ETSI.ARF.WorldStorage.REST Debug.Log($"[REST] Create Trackable {trackable.UUID}..."); - ResponseObject ro = new ResponseObject("Create Trackable " + trackable.Name + " (no UUID)", func); - apiClient.AddTrackableAsync(token, trackable, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + ResponseObject ro = new ResponseObject("Create Trackable " + trackable.Name + " (no UUID)", func); + apiClient.AddTrackableAsync(token, trackable, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } @@ -115,18 +115,18 @@ namespace ETSI.ARF.WorldStorage.REST apiClient = new WorldStorageClient(httpClient); Debug.Log($"[REST] Update Trackable {trackable.UUID}..."); - return apiClient.ModifyTrackable(token, trackable); + return apiClient.ModifyTrackable(token, trackable).Message; } - static public ResponseObject UpdateTrackableAsync(WorldStorageServer ws, Trackable trackable, Action> func) + static public ResponseObject UpdateTrackableAsync(WorldStorageServer ws, Trackable trackable, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); Debug.Log($"[REST] Update Trackable {trackable.UUID}..."); - ResponseObject ro = new ResponseObject("Update Trackable " + trackable.UUID.ToString(), func); - apiClient.ModifyTrackableAsync(token, trackable,ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + ResponseObject ro = new ResponseObject("Update Trackable " + trackable.UUID.ToString(), func); + apiClient.ModifyTrackableAsync(token, trackable,ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } @@ -137,18 +137,18 @@ namespace ETSI.ARF.WorldStorage.REST apiClient = new WorldStorageClient(httpClient); Debug.Log($"[REST] Delete Trackable {UUID}..."); - return apiClient.DeleteTrackable(token, UUID); + return apiClient.DeleteTrackable(token, UUID).Message; } - static public ResponseObject DeleteTrackableAsync(WorldStorageServer ws, Guid UUID, Action> func) + static public ResponseObject DeleteTrackableAsync(WorldStorageServer ws, Guid UUID, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); Debug.Log($"[REST] Delete Trackable {UUID}..."); - ResponseObject ro = new ResponseObject("Delete Trackable " + UUID.ToString(), func); - apiClient.DeleteTrackableAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + ResponseObject ro = new ResponseObject("Delete Trackable " + UUID.ToString(), func); + apiClient.DeleteTrackableAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } } diff --git a/Runtime/Scripts/REST/WorldAnchorRequest.cs b/Runtime/Scripts/REST/WorldAnchorRequest.cs index d6b2c95..07495de 100644 --- a/Runtime/Scripts/REST/WorldAnchorRequest.cs +++ b/Runtime/Scripts/REST/WorldAnchorRequest.cs @@ -63,18 +63,18 @@ namespace ETSI.ARF.WorldStorage.REST apiClient = new WorldStorageClient(httpClient); Debug.Log("[REST] Request WorldAnchors..."); - return apiClient.GetWorldAnchors(token); + return apiClient.GetWorldAnchors(token).WorldAnchors as List; } - static public ResponseObject> GetWorldAnchorsAsync(WorldStorageServer ws, Action>> func) + static public ResponseObject GetWorldAnchorsAsync(WorldStorageServer ws, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); Debug.Log("[REST] Request WorldAnchors..."); - ResponseObject> ro = new ResponseObject>("Request WorldAnchors", func); - apiClient.GetWorldAnchorsAsync(token, ro.cancellationToken).ContinueWith(OnReceiveListOfObjects, ro); + ResponseObject ro = new ResponseObject("Request WorldAnchors", func); + apiClient.GetWorldAnchorsAsync(token, ro.cancellationToken).ContinueWith(OnReceiveListOfObjects, ro); return ro; } @@ -89,10 +89,10 @@ namespace ETSI.ARF.WorldStorage.REST if (worldAnchor.CreatorUUID == Guid.Empty) worldAnchor.CreatorUUID = System.Guid.Parse("8fb169e2-8910-4cd5-a8f9-b7abff38d013"); Debug.Log($"[REST] Create WorldAnchor {worldAnchor.UUID}..."); - return apiClient.AddWorldAnchor(token, worldAnchor); + return apiClient.AddWorldAnchor(token, worldAnchor).Message; } - static public ResponseObject CreateWorldAnchorAsync(WorldStorageServer ws, WorldAnchor worldAnchor, Action> func) + static public ResponseObject CreateWorldAnchorAsync(WorldStorageServer ws, WorldAnchor worldAnchor, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); @@ -103,8 +103,8 @@ namespace ETSI.ARF.WorldStorage.REST if (worldAnchor.CreatorUUID == Guid.Empty) worldAnchor.CreatorUUID = System.Guid.Parse("8fb169e2-8910-4cd5-a8f9-b7abff38d013"); Debug.Log($"[REST] Create WorldAnchor {worldAnchor.UUID}..."); - ResponseObject ro = new ResponseObject("Create WorldAnchor " + worldAnchor.Name + " (no UUID)", func); - apiClient.AddWorldAnchorAsync(token, worldAnchor, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + ResponseObject ro = new ResponseObject("Create WorldAnchor " + worldAnchor.Name + " (no UUID)", func); + apiClient.AddWorldAnchorAsync(token, worldAnchor, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } @@ -115,18 +115,18 @@ namespace ETSI.ARF.WorldStorage.REST apiClient = new WorldStorageClient(httpClient); Debug.Log($"[REST] Update WorldAnchor {worldAnchor.UUID}..."); - return apiClient.ModifyWorldAnchor(token, worldAnchor); + return apiClient.ModifyWorldAnchor(token, worldAnchor).Message; } - static public ResponseObject UpdateWorldAnchorAsync(WorldStorageServer ws, WorldAnchor worldAnchor, Action> func) + static public ResponseObject UpdateWorldAnchorAsync(WorldStorageServer ws, WorldAnchor worldAnchor, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); Debug.Log($"[REST] Update WorldAnchor {worldAnchor.UUID}..."); - ResponseObject ro = new ResponseObject("Update WorldAnchor " + worldAnchor.UUID.ToString(), func); - apiClient.ModifyWorldAnchorAsync(token, worldAnchor, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + ResponseObject ro = new ResponseObject("Update WorldAnchor " + worldAnchor.UUID.ToString(), func); + apiClient.ModifyWorldAnchorAsync(token, worldAnchor, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } @@ -137,18 +137,18 @@ namespace ETSI.ARF.WorldStorage.REST apiClient = new WorldStorageClient(httpClient); Debug.Log($"[REST] Delete WorldAnchor {UUID}..."); - return apiClient.DeleteWorldAnchor(token, UUID); + return apiClient.DeleteWorldAnchor(token, UUID).Message; } - static public ResponseObject DeleteWorldAnchorAsync(WorldStorageServer ws, Guid UUID, Action> func) + static public ResponseObject DeleteWorldAnchorAsync(WorldStorageServer ws, Guid UUID, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); Debug.Log($"[REST] Delete WorldAnchor {UUID}..."); - ResponseObject ro = new ResponseObject("Delete WorldAnchor " + UUID.ToString(), func); - apiClient.DeleteWorldAnchorAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + ResponseObject ro = new ResponseObject("Delete WorldAnchor " + UUID.ToString(), func); + apiClient.DeleteWorldAnchorAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } } diff --git a/Runtime/Scripts/REST/WorldLinkRequest.cs b/Runtime/Scripts/REST/WorldLinkRequest.cs index 44b489f..d38e1d5 100644 --- a/Runtime/Scripts/REST/WorldLinkRequest.cs +++ b/Runtime/Scripts/REST/WorldLinkRequest.cs @@ -62,18 +62,18 @@ namespace ETSI.ARF.WorldStorage.REST apiClient = new WorldStorageClient(httpClient); Debug.Log("[REST] Request WorldLinks..."); - return apiClient.GetWorldLinks(token); + return apiClient.GetWorldLinks(token).WorldLinks as List; } - static public ResponseObject> GetWorldLinksAsync(WorldStorageServer ws, Action>> func) + static public ResponseObject GetWorldLinksAsync(WorldStorageServer ws, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); Debug.Log("[REST] Request WorldLinks..."); - ResponseObject> ro = new ResponseObject>("Request WorldLinks", func); - apiClient.GetWorldLinksAsync(token, ro.cancellationToken).ContinueWith(OnReceiveListOfObjects, ro); + ResponseObject ro = new ResponseObject("Request WorldLinks", func); + apiClient.GetWorldLinksAsync(token, ro.cancellationToken).ContinueWith(OnReceiveListOfObjects, ro); return ro; } @@ -88,10 +88,10 @@ namespace ETSI.ARF.WorldStorage.REST if (worldLink.CreatorUUID == Guid.Empty) worldLink.CreatorUUID = System.Guid.Parse("8fb169e2-8910-4cd5-a8f9-b7abff38d013"); Debug.Log($"[REST] Create WorldLink {worldLink.UUID}..."); - return apiClient.AddWorldLink(token, worldLink); + return apiClient.AddWorldLink(token, worldLink).Message; } - static public ResponseObject CreateWorldLinkAsync(WorldStorageServer ws, WorldLink worldLink, Action> func) + static public ResponseObject CreateWorldLinkAsync(WorldStorageServer ws, WorldLink worldLink, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); @@ -102,8 +102,8 @@ namespace ETSI.ARF.WorldStorage.REST if (worldLink.CreatorUUID == Guid.Empty) worldLink.CreatorUUID = System.Guid.Parse("8fb169e2-8910-4cd5-a8f9-b7abff38d013"); Debug.Log($"[REST] Create WorldLink {worldLink.UUID}..."); - ResponseObject ro = new ResponseObject("Create WorldLink (no UUID)", func); - apiClient.AddWorldLinkAsync(token, worldLink, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + ResponseObject ro = new ResponseObject("Create WorldLink (no UUID)", func); + apiClient.AddWorldLinkAsync(token, worldLink, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } @@ -114,18 +114,18 @@ namespace ETSI.ARF.WorldStorage.REST apiClient = new WorldStorageClient(httpClient); Debug.Log($"[REST] Update WorldLink {worldLink.UUID}..."); - return apiClient.ModifyWorldLink(token, worldLink); + return apiClient.ModifyWorldLink(token, worldLink).Message; } - static public ResponseObject UpdateWorldLinkAsync(WorldStorageServer ws, WorldLink worldLink, Action> func) + static public ResponseObject UpdateWorldLinkAsync(WorldStorageServer ws, WorldLink worldLink, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); Debug.Log($"[REST] Update WorldLink {worldLink.UUID}..."); - ResponseObject ro = new ResponseObject("Update WorldLink " + worldLink.UUID.ToString(), func); - apiClient.ModifyWorldLinkAsync(token, worldLink, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + ResponseObject ro = new ResponseObject("Update WorldLink " + worldLink.UUID.ToString(), func); + apiClient.ModifyWorldLinkAsync(token, worldLink, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } @@ -136,18 +136,18 @@ namespace ETSI.ARF.WorldStorage.REST apiClient = new WorldStorageClient(httpClient); Debug.Log($"[REST] Delete WorldLink {UUID}..."); - return apiClient.DeleteWorldLink(token, UUID); + return apiClient.DeleteWorldLink(token, UUID).Message; } - static public ResponseObject DeleteWorldLinkAsync(WorldStorageServer ws, Guid UUID, Action> func) + static public ResponseObject DeleteWorldLinkAsync(WorldStorageServer ws, Guid UUID, Action> func) { wsServer = ws; var httpClient = new UnityWebRequestHttpClient(ws.URI); apiClient = new WorldStorageClient(httpClient); Debug.Log($"[REST] Delete WorldLink {UUID}..."); - ResponseObject ro = new ResponseObject("Delete WorldLink " + UUID.ToString(), func); - apiClient.DeleteWorldLinkAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); + ResponseObject ro = new ResponseObject("Delete WorldLink " + UUID.ToString(), func); + apiClient.DeleteWorldLinkAsync(token, UUID, ro.cancellationToken).ContinueWith(OnReceiveObject, ro); return ro; } } -- GitLab From 595e4d929c13b84f79cc27bed2feffdae7a5b734 Mon Sep 17 00:00:00 2001 From: Sylvain Renault Date: Tue, 24 Sep 2024 12:41:37 +0200 Subject: [PATCH 13/13] Communication and access to WS server. --- Editor/Scripts/Windows/TrackableWindow.cs | 12 ++++++------ Editor/Scripts/Windows/WorldAnchorWindow.cs | 9 +++++---- Editor/Scripts/Windows/WorldLinkWindow.cs | 6 ++++-- Runtime/Scripts/GraphEditor/LinkVisual.cs | 2 +- Runtime/Scripts/OpenAPI/DataModels.cs | 8 ++++---- Runtime/Scripts/REST/AdminRequest.cs | 12 ++++++++++++ Runtime/Scripts/REST/RequestBase.cs | 8 ++++---- 7 files changed, 36 insertions(+), 21 deletions(-) diff --git a/Editor/Scripts/Windows/TrackableWindow.cs b/Editor/Scripts/Windows/TrackableWindow.cs index 38b7bf6..c5d8f57 100644 --- a/Editor/Scripts/Windows/TrackableWindow.cs +++ b/Editor/Scripts/Windows/TrackableWindow.cs @@ -219,13 +219,13 @@ namespace ETSI.ARF.WorldStorage.UI confidence = EditorGUILayout.DoubleField("Confidence:", confidence); EditorGUILayout.Space(); - trackableSize = EditorGUILayout.Vector3Field("Trackable Size:", trackableSize); - - EditorGUILayout.Space(); - GUILayout.Label("Local CRS:"); + GUILayout.Label("Transform (local CRS):"); localCRS_pos = EditorGUILayout.Vector3Field(" Position:", localCRS_pos); localCRS_rot = EditorGUILayout.Vector3Field(" Rotation:", localCRS_rot); + EditorGUILayout.Space(); + trackableSize = EditorGUILayout.Vector3Field("Trackable Size:", trackableSize); + EditorGUILayout.Space(); if (GUILayout.Button("Generate Dummy Payload")) { @@ -255,12 +255,12 @@ namespace ETSI.ARF.WorldStorage.UI public override void GetParams() { - customName = "Requesting information..."; - + //customName = "Requesting information..."; TrackableRequest.GetTrackableAsync(worldStorageServer, Guid.Parse(UUID), (response) => { Trackable obj = response.result; customName = obj.Name; + Debug.Log("name=" + customName); creatorUUID = obj.CreatorUUID.ToString(); type = obj.TrackableType; unit = obj.Unit; diff --git a/Editor/Scripts/Windows/WorldAnchorWindow.cs b/Editor/Scripts/Windows/WorldAnchorWindow.cs index 5e95874..a612081 100644 --- a/Editor/Scripts/Windows/WorldAnchorWindow.cs +++ b/Editor/Scripts/Windows/WorldAnchorWindow.cs @@ -212,13 +212,13 @@ namespace ETSI.ARF.WorldStorage.UI unit = (UnitSystem)EditorGUILayout.EnumPopup("Unit System:", unit); EditorGUILayout.Space(); - worldAnchorSize = EditorGUILayout.Vector3Field("Anchor Size:", worldAnchorSize); - - EditorGUILayout.Space(); - GUILayout.Label("Local CRS:"); + GUILayout.Label("Transform (local CRS):"); localCRS_pos = EditorGUILayout.Vector3Field(" Position:", localCRS_pos); localCRS_rot = EditorGUILayout.Vector3Field(" Rotation:", localCRS_rot); + EditorGUILayout.Space(); + worldAnchorSize = EditorGUILayout.Vector3Field("Anchor Size:", worldAnchorSize); + // --------------------- // Keyvalues // --------------------- @@ -237,6 +237,7 @@ namespace ETSI.ARF.WorldStorage.UI public override void GetParams() { + //customName = "Requesting information..."; WorldAnchorRequest.GetWorldAnchorAsync(worldStorageServer, Guid.Parse(UUID), (response) => { WorldAnchor obj = response.result; diff --git a/Editor/Scripts/Windows/WorldLinkWindow.cs b/Editor/Scripts/Windows/WorldLinkWindow.cs index 0dbb9be..99cf17f 100644 --- a/Editor/Scripts/Windows/WorldLinkWindow.cs +++ b/Editor/Scripts/Windows/WorldLinkWindow.cs @@ -49,6 +49,7 @@ namespace ETSI.ARF.WorldStorage.UI [SerializeField] public List anchors = new List(); private static GUILayoutOption miniButtonWidth = GUILayout.Width(50); + private static GUILayoutOption middleButtonWidth = GUILayout.Width(70); // World Anchors params string UUID = System.Guid.Empty.ToString(); @@ -351,7 +352,7 @@ namespace ETSI.ARF.WorldStorage.UI } GUI.backgroundColor = WorldStorageWindow.arfColors[0]; - if (GUILayout.Button("Request", EditorStyles.miniButtonLeft, miniButtonWidth) || lastFromUUID != FROM.UUID) + if (GUILayout.Button(" Request ", EditorStyles.miniButtonLeft, middleButtonWidth) || lastFromUUID != FROM.UUID) { GetElementFROM(); } @@ -373,7 +374,7 @@ namespace ETSI.ARF.WorldStorage.UI TO.UUID = TO.UUID.Split('[', ']')[1]; } GUI.backgroundColor = WorldStorageWindow.arfColors[0]; - if (GUILayout.Button("Request", EditorStyles.miniButtonLeft, miniButtonWidth) || lastToUUID != TO.UUID) + if (GUILayout.Button("Request ", EditorStyles.miniButtonLeft, middleButtonWidth) || lastToUUID != TO.UUID) { GetElementTO(); } @@ -410,6 +411,7 @@ namespace ETSI.ARF.WorldStorage.UI public override void GetParams() { + //customName = "Requesting information..."; WorldLinkRequest.GetWorldLinkAsync(worldStorageServer, Guid.Parse(UUID), (response) => { WorldLink obj = response.result; diff --git a/Runtime/Scripts/GraphEditor/LinkVisual.cs b/Runtime/Scripts/GraphEditor/LinkVisual.cs index 2acf9d7..48515cb 100644 --- a/Runtime/Scripts/GraphEditor/LinkVisual.cs +++ b/Runtime/Scripts/GraphEditor/LinkVisual.cs @@ -30,7 +30,7 @@ namespace ETSI.ARF.WorldStorage.UI { Debug.Log("Rien à tracer"); } - } #endif + } } } diff --git a/Runtime/Scripts/OpenAPI/DataModels.cs b/Runtime/Scripts/OpenAPI/DataModels.cs index 17f60fe..c3f776e 100644 --- a/Runtime/Scripts/OpenAPI/DataModels.cs +++ b/Runtime/Scripts/OpenAPI/DataModels.cs @@ -24,7 +24,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage Name = name; } - public string ToJson() { return JsonUtility.ToJson(this); } + public string ToJson() { return Newtonsoft.Json.JsonConvert.SerializeObject(this); } } // @@ -38,7 +38,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage Name = name; } - public string ToJson() { return JsonUtility.ToJson(this); } + public string ToJson() { return Newtonsoft.Json.JsonConvert.SerializeObject(this); } } public partial class WorldAnchor : IModel @@ -49,7 +49,7 @@ namespace ETSI.ARF.OpenAPI.WorldStorage Name = name; } - public string ToJson() { return JsonUtility.ToJson(this); } + public string ToJson() { return Newtonsoft.Json.JsonConvert.SerializeObject(this); } } public partial class WorldLink : IModel @@ -59,6 +59,6 @@ namespace ETSI.ARF.OpenAPI.WorldStorage UUID = Guid.NewGuid(); } - public string ToJson() { return JsonUtility.ToJson(this); } + public string ToJson() { return Newtonsoft.Json.JsonConvert.SerializeObject(this); } } } \ No newline at end of file diff --git a/Runtime/Scripts/REST/AdminRequest.cs b/Runtime/Scripts/REST/AdminRequest.cs index 4ab8496..a7bbac6 100644 --- a/Runtime/Scripts/REST/AdminRequest.cs +++ b/Runtime/Scripts/REST/AdminRequest.cs @@ -29,6 +29,18 @@ namespace ETSI.ARF.WorldStorage.REST { public class AdminRequest : RequestBase { + #region Test methods + static public void CheckServer(WorldStorageServer ws) + { + string ping = AdminRequest.PingSync(ws); + string state = AdminRequest.AdminSync(ws); + string ver = AdminRequest.VersionSync(ws); + Debug.Log("[REST] WA Ping: " + ping); + Debug.Log("[REST] WA State: " + state); + Debug.Log("[REST] WA Version: " + ver); + } + #endregion + // // Wrapper for the endpoints // diff --git a/Runtime/Scripts/REST/RequestBase.cs b/Runtime/Scripts/REST/RequestBase.cs index 8a369f5..f06a668 100644 --- a/Runtime/Scripts/REST/RequestBase.cs +++ b/Runtime/Scripts/REST/RequestBase.cs @@ -82,18 +82,18 @@ namespace ETSI.ARF.WorldStorage.REST cnt++; } } - else if (o.GetType() == typeof(WorldAnchorsResponse)) + else if (o.result.GetType() == typeof(WorldAnchorsResponse)) { - WorldAnchorsResponse res = o as WorldAnchorsResponse; + WorldAnchorsResponse res = o.result as WorldAnchorsResponse; foreach (var item in res.WorldAnchors) { listOfObjects.Add(item.UUID, item); cnt++; } } - else if (o.GetType() == typeof(WorldLinksResponse)) + else if (o.result.GetType() == typeof(WorldLinksResponse)) { - WorldLinksResponse res = o as WorldLinksResponse; + WorldLinksResponse res = o.result as WorldLinksResponse; foreach (var item in res.WorldLinks) { listOfObjects.Add(item.UUID, item); -- GitLab