using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; using TMPro; using Newtonsoft.Json; using WebSocketSharp; using ETSI.ARF.WorldStorage; using ETSI.ARF.WorldStorage.REST; using ETSI.ARF.WorldAnalysis; using ETSI.ARF.WorldAnalysis.REST; using ETSI.ARF.OpenAPI.WorldAnalysis; using Pose = ETSI.ARF.OpenAPI.WorldAnalysis.Pose; using static WorldAnalysisInterface; public class ServerMaintenanceClient : MonoBehaviour { static public string token = "dev"; static public string session = "HHI"; public GameObject floatingLogo; /// <summary> /// UUID of the node or trackable /// </summary> public string ARFMainNodeUUID; [Space(8)] public WorldStorageServer worldStorageServer; public WorldAnalysisREST waRESTServer; [Space(8)] public TMP_Text console; public GameObject asset1; string consoleText = "<B>ETSI ISG-ARF Client Console (STF 669)</B>\n"; bool isConsoleText = false; int validity = int.MaxValue; // Track this trackable/anchor Guid uuidTarget = Guid.Empty; // Subscription id Guid uuidSub = Guid.Empty; // Thread safe bool updateTransformMatrix = false; bool updateTransformQuat = false; Matrix4x4 matrix; ETSI.ARF.OpenAPI.WorldAnalysis.VectorQuaternionPoseValue quat; // Start is called before the first frame update void Start() { Instance = waRESTServer; if (asset1 != null) asset1.GetComponent<Renderer>().material.color = Color.red; uuidTarget = Guid.Parse(ARFMainNodeUUID); ETSI.ARF.WorldStorage.REST.AdminRequest.CheckServer(worldStorageServer); ETSI.ARF.WorldAnalysis.REST.AdminRequest.CheckServer(waRESTServer.waServer); consoleText += "World Storage server: " + worldStorageServer.URI + "... connected!\n"; consoleText += "World Analysis server: " + waRESTServer.waServer.URI + "... connected!\n"; isConsoleText = true; Capability[] caps; if (waRESTServer.GetCapabilities(token, out caps) == CapabilityResult.OK) { waRESTServer.PrintCapabilities(caps); consoleText += "<B>Capabilities of World Analysis modules:</B>\n"; if (caps.Length == 0) { consoleText += "No capabilities!\n"; } else foreach (var item in caps) { consoleText += " Type: " + item.TrackableType.ToString() + " Acc: " + item.Accuracy.ToString() + " FPS: " + item.Framerate + "\n"; } consoleText += "\n"; isConsoleText = true; } consoleText += "Subscription of ARF objects (Trackables and World Anchrors)... OK\n"; isConsoleText = true; /* bool isSupported = false; TypeWorldStorage wsType; Capability[] capsOfUUID; if (waRESTServer.GetCapability(token, uuidTarget, out isSupported, out wsType, out capsOfUUID) == CapabilityResult.OK) { waRESTServer.PrintCapabilities(capsOfUUID); consoleText += "\nCapabilities for UUID=" + uuidTarget.ToString() + ":\n"; if (caps.Length == 0) { consoleText += "No capabilities!\n"; } else foreach (var item in capsOfUUID) { consoleText += " " + item.TrackableType.ToString() + " fps=" + item.Framerate + "\n"; } } else consoleText += "No capabilities found!\n"; isConsoleText = true; */ } // Update is called once per frame bool updateAsset1 = false; Color asset1Color = Color.grey; void Update() { if (Keyboard.current.spaceKey.wasPressedThisFrame) { //webSocket.Send("PoseStart:10"); } if (isConsoleText) { isConsoleText = false; console.text = consoleText; } if (updateAsset1) { updateAsset1 = false; //asset1.GetComponent<Renderer>().material.color = asset1Color; } // Thread safe if (updateTransformMatrix) { updateTransformMatrix = false; if (floatingLogo != null) floatingLogo.transform.SetPositionAndRotation(matrix.GetPosition(), matrix.rotation); } else if (updateTransformQuat) { updateTransformQuat = false; if (floatingLogo != null) floatingLogo.transform.position = WorldAnalysisUnityHelper.ConvertETSIVector3ToUnity(quat.Position); if (floatingLogo != null) floatingLogo.transform.rotation = WorldAnalysisUnityHelper.ConvertETSIARFQuaternionToUnity(quat.Rotation); } } public void QuitApplication() { #if UNITY_EDITOR // Application.Quit() does not work in the editor so // UnityEditor.EditorApplication.isPlaying need to be set to false to end the game UnityEditor.EditorApplication.isPlaying = false; #else Application.Quit(); #endif } private void OnDestroy() { SubscribeToPose(false); } public void SubscribeToPose(bool yes = true) { if (yes) { InformationSubscriptionResult response = waRESTServer.SubscribeToPose(token, uuidTarget, Mode_WorldAnalysis.TRACKABLES_TO_DEVICE, PoseCallback, ref validity, out uuidSub); if (response == InformationSubscriptionResult.OK) { SetColor(Color.yellow); } else SetColor(Color.red); } else { if (uuidSub != Guid.Empty) waRESTServer.UnsubscribeFromPose(uuidSub); uuidSub = Guid.Empty; SetColor(Color.red); } } public void OnButtonPoseStart() { SubscribeToPose(true); } public void OnButtonPoseStop() { SubscribeToPose(false); } public void OnButtonSendUserPose() { UnityEngine.Vector3 newPos = Camera.main.transform.position; UnityEngine.Quaternion newRot = Camera.main.transform.rotation; //Pose value VectorQuaternionPoseValue newPoseValue = new VectorQuaternionPoseValue(); newPoseValue.Type = PoseValueType.VECTOR_QUATERNION; newPoseValue.Unit = UnitSystem.M; newPoseValue.Position = new ETSI.ARF.OpenAPI.WorldAnalysis.Vector3(newPos.x, newPos.y, newPos.z); newPoseValue.Rotation = new ETSI.ARF.OpenAPI.WorldAnalysis.Quaternion(newRot.x, newRot.y, newRot.z, newRot.w); Pose user = new Pose(); user.Uuid = Guid.Parse(worldStorageServer.currentUser.UUID); user.Value = newPoseValue; string json = Newtonsoft.Json.JsonConvert.SerializeObject(user); Debug.Log("[WS] Sending user's pose: " + json); waRESTServer.WebSocketClient_Send("CurrentUserPose=" + json); } void SetColor(Color c) { asset1Color = c; updateAsset1 = true; } public void MessageCallback(string messageFromServer) { // // Is something from the WebSocket to be observed? // if (messageFromServer.StartsWith("Time=")) { Debug.Log("[CLIENT] Server time is: " + messageFromServer.Split('=')[1]); // test the communication consoleText += "Server time is: " + messageFromServer.Split('=')[1] + "\n"; isConsoleText = true; } } public void PoseCallback(PoseEstimationResult result, Pose pose) { switch (result) { case PoseEstimationResult.OK: //Debug.Log($"Updating UUID { pose.Uuid } from subscription."); SetColor(Color.green); if (pose.Value.Type == PoseValueType.MATRIX) { // Workaround (Thread safe) //MatrixPoseValue m = (MatrixPoseValue)pose.Value; string v = JsonConvert.SerializeObject(pose.Value); MatrixPoseValue value = JsonConvert.DeserializeObject<MatrixPoseValue>(v); if (value.Transform.Count == 16) { matrix = WorldAnalysisUnityHelper.ConvertETSIARFTransform3DToUnity(value.Transform); updateTransformMatrix = true; } else { // Ignore a wrong pose } } else if (pose.Value.Type == ETSI.ARF.OpenAPI.WorldAnalysis.PoseValueType.VECTOR_QUATERNION) { // Workaround (Thread safe) //VectorQuaternionPoseValue value = (ETSI.ARF.OpenAPI.WorldAnalysis.VectorQuaternionPoseValue)pose.Value; string v = JsonConvert.SerializeObject(pose.Value); quat = JsonConvert.DeserializeObject<VectorQuaternionPoseValue>(v); updateTransformQuat = true; } else { Debug.LogWarning("Pose value type not supported yet :" + pose.Value.Type); // Todo : manage other types } break; case PoseEstimationResult.NONE: SetColor(Color.yellow); break; default: SetColor(Color.red); break; } } }