public Scene(SceneSerialization sceneSerialization, ListBox listBox, Size size)
        {
            cameras         = new List <Camera>();
            renderObjects3D = new List <IRenderObject3D>();
            lights          = new List <Light>();
            this.listBox    = listBox;

            foreach (var renderObject3D in sceneSerialization.RenderObjects3D)
            {
                Add(renderObject3D);
                renderObject3D.OnDeserialization(this);
            }

            foreach (var light in sceneSerialization.Lights)
            {
                Add(light);
                light.OnDeserialization(this);
            }

            foreach (var camera in sceneSerialization.Cameras)
            {
                Add(camera);
                camera.OnDeserialization(this);
            }

            Camera        = cameras[cameras.Count - 1];
            Camera.Aspect = size.Width / (float)size.Height;
        }
Exemple #2
0
        static void SaveProjects(ProjectList projectList)
        {
            var jsonData = SceneSerialization.ToJson(projectList);

            File.WriteAllText(projectListFilePath, jsonData);

            ProjectListSaved?.Invoke(projectList);
        }
        public static ProxyListViewData CreateProxyListViewData(Proxy proxy, ref int autoIncrement, int depth = 0)
        {
            string transformPath  = null;
            var    gameObject     = proxy.gameObject;
            var    prefabMetadata = gameObject.GetComponentInParent <PrefabMetadata>();

            if (prefabMetadata != null)
            {
                transformPath = prefabMetadata.transform.GetTransformPath(gameObject.transform);
            }

            var proxyData = new ProxyListViewData(k_ProxyGameObjectItemTemplate, proxy, autoIncrement++, depth, prefabMetadata, transformPath);
            var children  = new List <ProxyListViewData>();

            proxyData.children = children;

            if (PropertyContainer.TryGetProperty(ref gameObject, new PropertyPath(k_ActivePropertyPath), out var activeProperty))
            {
                children.Add(PropertyToPropertyData((Property <GameObject, bool>)activeProperty, ref gameObject,
                                                    autoIncrement++, k_ActivePropertyPath, prefabMetadata, transformPath));
            }

            if (PropertyContainer.TryGetProperty(ref gameObject, new PropertyPath(k_NamePropertyPath), out var nameProperty))
            {
                children.Add(PropertyToPropertyData((Property <GameObject, string>)nameProperty, ref gameObject,
                                                    autoIncrement++, k_NamePropertyPath, prefabMetadata, transformPath));
            }

#if !NET_DOTS && !ENABLE_IL2CPP
            SceneSerialization.RegisterPropertyBag(typeof(Proxy));
#endif

            if (PropertyContainer.TryGetProperty(ref proxy, new PropertyPath(k_ColorPropertyPath), out var colorProperty))
            {
                children.Add(PropertyToPropertyData((Property <Proxy, Color>)colorProperty, ref proxy, autoIncrement++,
                                                    k_ColorPropertyPath, prefabMetadata, transformPath));
            }

            var components = gameObject.GetComponents <ICondition>();
            foreach (var condition in components)
            {
                if (condition == null)
                {
                    continue;
                }

                if (!(condition is Component component))
                {
                    continue;
                }

                var componentIndex = GetComponentIndex(component);
                CreateProxyListViewData(component, componentIndex, prefabMetadata, transformPath, children, ref autoIncrement);
            }

            return(proxyData);
        }
        static RequestHandle SaveMarker(this IUsesCloudStorage storageUser, CompanionProject project,
                                        string resourceFolder, string guid, Marker marker, Action <bool, string> callback)
        {
            var jsonText = SceneSerialization.ToJson(marker);

            WriteLocalMarker(project, resourceFolder, guid, jsonText);
            var key = GetMarkerKey(resourceFolder, guid);

            if (!project.linked)
            {
                callback?.Invoke(true, key);
                return(default);
        static RequestHandle SaveEnvironment(this IUsesCloudStorage storageUser, CompanionProject project,
                                             string resourceFolder, string guid, Environment environment, Action <bool, string, long> callback)
        {
            var jsonText = SceneSerialization.ToJson(environment);

            // Write to local storage in case cloud isn't reachable
            WriteLocalEnvironment(project, resourceFolder, guid, jsonText);
            var key = GetEnvironmentKey(resourceFolder, guid);

            if (!project.linked)
            {
                callback?.Invoke(true, key, jsonText.Length);
                return(default);
        static RequestHandle SaveDataRecording(this IUsesCloudStorage storageUser, CompanionProject project, string resourceFolder,
                                               string guid, CompanionDataRecording recording, Action <bool, string, long> callback, ProgressCallback progress)
        {
            var jsonText = SceneSerialization.ToJson(recording);

            WriteLocalDataRecording(project, resourceFolder, guid, jsonText);

            var key = GetDataRecordingKey(resourceFolder, guid);

            if (!project.linked)
            {
                callback?.Invoke(true, key, jsonText.Length);
                return(default);
        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var dialog = new SaveFileDialog();

            dialog.Filter   = "GK4 files (*.gk4)|*GK4";
            dialog.FileName = "scene1.gk4";

            if (dialog.ShowDialog() == DialogResult.OK)
            {
                using (var stream = dialog.OpenFile())
                {
                    SceneSerialization.Serialize(stream, scene.ToSceneSerialization());
                }
            }
        }
        private void loadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var dialog = new OpenFileDialog();

            dialog.Filter = "GK4 files (*.gk4)|*GK4";

            if (dialog.ShowDialog() == DialogResult.OK)
            {
                using (var stream = dialog.OpenFile())
                {
                    objectsListBox.Items.Clear();
                    editObjectsGroupBox.Controls.Clear();

                    scene = new Scene(SceneSerialization.Deserialize(stream), objectsListBox, viewSize);
                }
            }
        }
Exemple #9
0
        static void OpenJsonScene()
        {
            var path = EditorUtility.OpenFilePanel("Open JSON scene", Application.dataPath, k_Extension);

            if (!string.IsNullOrEmpty(path))
            {
                if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
                {
                    return;
                }

                var assetPackPath = Path.ChangeExtension(path, ".asset");
                assetPackPath = assetPackPath.Replace(Application.dataPath, "Assets");
                var assetPack = AssetDatabase.LoadAssetAtPath <AssetPack>(assetPackPath);
                var jsonText  = File.ReadAllText(path);
                var scene     = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene);
                SceneSerialization.ImportScene(jsonText, assetPack);
                scene.name = Path.GetFileNameWithoutExtension(path);
            }
        }
Exemple #10
0
        public static ProjectList LoadProjects()
        {
            var filePath = projectListFilePath;

            try
            {
                if (File.Exists(filePath))
                {
                    var jsonData = File.ReadAllText(filePath);
                    if (!string.IsNullOrEmpty(jsonData))
                    {
                        return(SceneSerialization.FromJson <ProjectList>(jsonData));
                    }
                }
            }
            catch (Exception e)
            {
                Debug.LogException(e);
            }

            return(new ProjectList());
        }
        static void CreateProxyListViewData(Component component, int componentIndex, PrefabMetadata prefabMetadata,
                                            string transformPath, List <ProxyListViewData> listViewData, ref int autoIncrement, int depth = 0)
        {
#if !NET_DOTS && !ENABLE_IL2CPP
            SceneSerialization.RegisterPropertyBagRecursively(component.GetType());
#endif

            var componentProperty = new ProxyListViewData(k_ComponentTemplate, component,
                                                          autoIncrement++, depth, prefabMetadata, transformPath, componentIndex);

            listViewData.Add(componentProperty);

            var optionalPropertyPathVisitor = new OptionalConstraintPropertyPathGetterVisitor();
            PropertyContainer.Visit(component, optionalPropertyPathVisitor);

            var optionalPropertyVisitor = new OptionalConstraintPropertyGetterVisitor
            {
                OptionalConstraintProperties = optionalPropertyPathVisitor.OptionalConstraintProperties
            };

            PropertyContainer.Visit(component, optionalPropertyVisitor);

            var visitor = new PropertyGetterVisitor
            {
                ParentData     = componentProperty,
                PrefabMetadata = prefabMetadata,
                TransformPath  = transformPath,
                ComponentIndex = componentIndex,
                AutoIncrement  = autoIncrement,
                OptionalConstraintProperties     = optionalPropertyPathVisitor.OptionalConstraintProperties,
                OptionalConstraintBoolProperties = optionalPropertyVisitor.OptionalConstraintBoolProperties
            };

            PropertyContainer.Visit(component, visitor);
            autoIncrement = visitor.AutoIncrement;
        }
Exemple #12
0
        static void SaveJsonScene()
        {
            var activeScene = SceneManager.GetActiveScene();

            if (!activeScene.IsValid())
            {
                return;
            }

            var path = EditorUtility.SaveFilePanel(
                "Save scene as JSON",
                Application.dataPath,
                activeScene.name,
                k_Extension);

            if (string.IsNullOrEmpty(path))
            {
                return;
            }

            var assetPackPath = Path.ChangeExtension(path, ".asset");

            assetPackPath = assetPackPath.Replace(Application.dataPath, "Assets");

            var assetPack = AssetDatabase.LoadAssetAtPath <AssetPack>(assetPackPath);
            var created   = false;

            if (assetPack == null)
            {
                created   = true;
                assetPack = ScriptableObject.CreateInstance <AssetPack>();
            }
            else
            {
                assetPack.Clear();
            }

            var sceneAsset = AssetDatabase.LoadAssetAtPath <SceneAsset>(activeScene.path);

            if (sceneAsset != null)
            {
                assetPack.SceneAsset = sceneAsset;
            }

            File.WriteAllText(path, SceneSerialization.SerializeScene(activeScene, assetPack));

            if (created)
            {
                if (assetPack.AssetCount > 0)
                {
                    AssetDatabase.CreateAsset(assetPack, assetPackPath);
                }
            }
            else
            {
                if (assetPack.AssetCount > 0)
                {
                    EditorUtility.SetDirty(assetPack);
                }
                else if (AssetDatabase.LoadAssetAtPath <AssetPack>(assetPackPath) != null)
                {
                    AssetDatabase.DeleteAsset(assetPackPath);
                }
            }

            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
        static void ImportEnvironment(string environmentName, string jsonText, string path,
                                      GameObject simulatedPlanePrefab, Material simulatedPlaneMaterial, Post postPrefab, MeshFilter meshPrefab,
                                      GameObject simulatedLightingPrefab, Action <UnityObject> callback)
        {
            var environment = SceneSerialization.FromJson <Environment>(jsonText);
            var height      = environment.height;
            var vertices    = environment.vertices;
            var center      = Vector3.zero;
            var posts       = CollectionPool <List <Post>, Post> .GetCollection();

            var  count    = vertices.Count;
            Post previous = null;

            foreach (var vertex in vertices)
            {
                var post = UnityObject.Instantiate(postPrefab);
                posts.Add(post);
                center += vertex;
                var postTransform = post.transform;
                postTransform.position = vertex;
                post.SetTopSphereHeight(height);

                if (previous != null)
                {
                    previous.Setup();
                    var previousPosition = previous.transform.position;
                    previous.UpdateWall(vertex, previousPosition - vertex, height);
                }

                previous = post;
            }

            if (count != 0)
            {
                center /= count;
            }

            var prefabRoot = new GameObject(environmentName).transform;
            var floorPlan  = new GameObject("Floor Plan").transform;

            prefabRoot.position = center;
            floorPlan.SetParent(prefabRoot, false);
            foreach (var post in posts)
            {
                post.transform.SetParent(floorPlan, true);
                var wall = post.Wall;
                if (wall != null)
                {
                    wall.SetParent(floorPlan, true);
                }
            }

            var planesRoot = new GameObject("Planes").transform;

            planesRoot.SetParent(prefabRoot, false);
            foreach (var plane in environment.planes)
            {
                var synthesizedPlane = ((GameObject)PrefabUtility.InstantiatePrefab(simulatedPlanePrefab, planesRoot)).GetComponent <SynthesizedPlane>();
                synthesizedPlane.transform.SetWorldPose(plane.pose);
                synthesizedPlane.SetMRPlaneData(plane.vertices, plane.center, plane.extents);
                synthesizedPlane.transform.SetParent(planesRoot, true);
                var renderer = synthesizedPlane.GetComponentInChildren <Renderer>();
                renderer.AddMaterial(simulatedPlaneMaterial);
            }

            var meshCapture = environment.MeshCapture;

            if (meshCapture.Meshes.Count > 0)
            {
                var meshesRoot = new GameObject("Meshes").transform;
                meshesRoot.SetParent(prefabRoot, false);
                var meshPath = EditorUtility.SaveFilePanelInProject(k_SaveMeshDialogTitle, environmentName, "asset", string.Empty);
                var index    = 0;
                foreach (var segment in meshCapture.Meshes)
                {
                    var meshFilter = UnityObject.Instantiate(meshPrefab, meshesRoot);
                    var mesh       = new Mesh {
                        name = $"Mesh Segment {index}"
                    };
                    mesh.SetVertices(segment.Vertices);
                    mesh.SetIndices(segment.Indices, MeshTopology.Triangles, 0);
                    mesh.SetNormals(segment.Normals);
                    meshFilter.transform.SetWorldPose(segment.Pose);
                    meshFilter.sharedMesh = mesh;
                    if (index == 0)
                    {
                        AssetDatabase.CreateAsset(mesh, meshPath);
                        AssetDatabase.SetMainObject(mesh, meshPath);
                    }
                    else
                    {
                        AssetDatabase.AddObjectToAsset(mesh, meshPath);
                    }

                    index++;
                }

                AssetDatabase.SaveAssets();
            }

            var environmentBounds    = BoundsUtils.GetBounds(prefabRoot);
            var prefabRootGameObject = prefabRoot.gameObject;
            var environmentSettings  = prefabRootGameObject.AddComponent <MARSEnvironmentSettings>();
            var environmentInfo      = environmentSettings.EnvironmentInfo;

            environmentInfo.EnvironmentBounds = environmentBounds;
            center = environmentBounds.center;
            var extents = environmentBounds.extents * 0.9f; // Reduce offset to avoid sim starting pose warning

            environmentInfo.DefaultCameraPivot = center;
            var cameraPose = new Pose(center + extents, Quaternion.LookRotation(-extents));

            environmentInfo.DefaultCameraWorldPose = cameraPose;
            environmentInfo.DefaultCameraSize      = environmentBounds.size.magnitude;
            environmentSettings.SetSimulationStartingPose(cameraPose, false);
            environmentSettings.UpdatePrefabInfo();
            UnityObject.Instantiate(simulatedLightingPrefab, prefabRoot);

            var prefab = PrefabUtility.SaveAsPrefabAssetAndConnect(prefabRootGameObject, path, InteractionMode.AutomatedAction);

            UnityObject.DestroyImmediate(prefabRootGameObject);
            AssetDatabase.SetLabels(prefab, new[] { MARSEnvironmentManager.EnvironmentLabel });
            ModuleLoaderCore.instance.GetModule <MARSEnvironmentManager>().UpdateSimulatedEnvironmentCandidates();
            callback(prefab);

            CollectionPool <List <Post>, Post> .RecycleCollection(posts);
        }
            public object Construct(Type type, UnsafeValueView view)
            {
                if (type != typeof(Component) || m_GameObject == null)
                {
                    return(null);
                }

                try
                {
                    var componentType = m_GenericConstructor.GetSerializedType();
                    if (componentType == null)
                    {
                        return(null);
                    }

#if !NET_DOTS && !ENABLE_IL2CPP
                    SceneSerialization.RegisterPropertyBag(componentType);
#endif

                    var properties = PropertyBagStore.GetPropertyBag(componentType);
                    if (properties == null)
                    {
                        Debug.LogWarning($"Could not resolve component type {componentType} deserializing {m_GameObject.name}. Will preserve serialized contents as JSON string");
                        return(CreateMissingComponent(view));
                    }

                    if (componentType == typeof(MissingComponent))
                    {
                        try
                        {
                            var value   = new JsonObject();
                            var visitor = new JsonSceneReader(m_SerializationMetadata);
                            visitor.SetView(view);
                            PropertyContainer.Visit(ref value, visitor);
                            var jsonString = value[nameof(MissingComponent.JsonString)].ToString();

                            // For some reason, newlines are read as null characters which break parsing
                            jsonString = jsonString.Replace('\0', '\n');

                            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString)))
                            {
                                using (var reader = new SerializedObjectReader(stream))
                                {
                                    reader.Read(out var document);
                                    var componentVisitor = new ComponentVisitor(m_GameObject, document.AsUnsafe(),
                                                                                null, m_SerializationMetadata);

                                    Component missingComponent = null;
                                    componentVisitor.ReadValue(ref missingComponent, document.AsUnsafe());
                                    return(missingComponent);
                                }
                            }
                        }
                        catch (Exception e)
                        {
                            Debug.Log($"Encountered an exception trying to deserialize MissingComponent. Preserving it as-is. Exception follows:\n{e}");
                        }
                    }

                    return(componentType == typeof(Transform) ? m_GameObject.GetComponent <Transform>() : m_GameObject.AddComponent(componentType));
                }
                catch (ArgumentException)
                {
                    Debug.LogWarning($"Could not resolve component type deserializing {m_GameObject.name}. Will preserve serialized contents as JSON string");
                    return(CreateMissingComponent(view));
                }
            }
Exemple #15
0
        protected void ReadValue <TValue>(ref TValue value, UnsafeValueView view, bool isRoot = false)
        {
            switch (view.Type)
            {
            case TokenType.String:
            {
                TypeConversion.TryConvert(view.AsStringView().ToString(), out value);
                break;
            }

            case TokenType.Primitive:
            {
                var p = view.AsPrimitiveView();

                if (p.IsIntegral())
                {
                    if (p.IsSigned())
                    {
                        TypeConversion.TryConvert(p.AsInt64(), out value);
                    }
                    else if (value is long)
                    {
                        TypeConversion.TryConvert(p.AsInt64(), out value);
                    }
                    else
                    {
                        TypeConversion.TryConvert(p.AsUInt64(), out value);
                    }
                }
                else if (p.IsDecimal() || p.IsInfinity() || p.IsNaN())
                {
                    TypeConversion.TryConvert(p.AsFloat(), out value);
                }
                else if (p.IsBoolean())
                {
                    TypeConversion.TryConvert(p.AsBoolean(), out value);
                }
                else if (p.IsNull())
                {
                    value = default;
                }

                break;
            }

            default:
            {
                var metadata = view.Type == TokenType.Object ? GetSerializedContainerMetadata(view.AsObjectView()) : default;

                m_SerializedTypeProvider.View           = view;
                m_SerializedTypeProvider.SerializedType = isRoot ? m_SerializedType : null;

                try
                {
                    var customValue = m_CustomTypeConstructor?.Construct(typeof(TValue), view);
                    if (customValue != null)
                    {
                        value = (TValue)customValue;
                    }

                    if (value == null)
                    {
                        DefaultTypeConstruction.Construct(ref value, m_SerializedTypeProvider);
                    }
                }
                catch (ArgumentException e)
                {
                    m_SerializedTypeProvider.Events.Add(new DeserializationEvent(EventType.Exception, new ArgumentException(e.Message)));
                    return;
                }

                using (new SerializedContainerMetadataScope(this, metadata))
                    using (new UnsafeViewScope(this, view))
                    {
                        var type = value?.GetType();
#if !NET_DOTS && !ENABLE_IL2CPP
                        if (type != null)
                        {
                            SceneSerialization.RegisterPropertyBag(type);
                        }
#endif

                        if (!PropertyContainer.Visit(ref value, this, out var errorCode))
                        {
                            switch (errorCode)
                            {
                            case VisitErrorCode.NullContainer:
                                throw new ArgumentNullException(nameof(value));

                            case VisitErrorCode.InvalidContainerType:
                                throw new InvalidContainerTypeException(type);

                            case VisitErrorCode.MissingPropertyBag:
                                throw new MissingPropertyBagException(type);

                            default:
                                throw new Exception($"Unexpected {nameof(VisitErrorCode)}=[{errorCode}]");
                            }
                        }
                    }

                break;
            }
            }
        }
        static IEnumerator ImportDataRecording(this IUsesCloudStorage storageUser, string recordingPath,
                                               string recordingKey, string recordingName, string jsonText, Stack <RequestHandle> requests,
                                               Action <UnityObject> callback)
        {
            k_DataRecordings.Clear();
            k_NewAssets.Clear();

            var recording = SceneSerialization.FromJson <CompanionDataRecording>(jsonText);

            var recordingInfo = SessionRecordingUtils.CreateSessionRecordingAsset(recordingPath);
            var timeline      = recordingInfo.Timeline;

            recordingInfo.name            = recordingName + " Info";
            recordingInfo.CloudResourceId = recordingKey;

            var resourceCount = 0;

            if (recording.HasCameraPath)
            {
                resourceCount++;
                requests.Push(storageUser.DownloadCameraPath(recordingKey, (success, list) =>
                {
                    if (success && list != null && list.Count > 0)
                    {
                        k_CameraPoseRecorder.PoseEvents = list;
                        var dataRecording = k_CameraPoseRecorder.TryCreateDataRecording(timeline, k_NewAssets);
                        if (dataRecording != null)
                        {
                            k_DataRecordings.Add(dataRecording);
                        }
                    }

                    // ReSharper disable once AccessToModifiedClosure
                    resourceCount--;
                }));
            }

            if (recording.HasPlaneData)
            {
                resourceCount++;
                requests.Push(storageUser.DownloadPlaneData(recordingKey, (success, list) =>
                {
                    if (success && list != null && list.Count > 0)
                    {
                        k_PlaneFindingRecorder.PlaneEvents = list;
                        var dataRecording = k_PlaneFindingRecorder.TryCreateDataRecording(timeline, k_NewAssets);
                        if (dataRecording != null)
                        {
                            k_DataRecordings.Add(dataRecording);
                        }
                    }

                    resourceCount--;
                }));
            }

            if (recording.HasPointCloud)
            {
                resourceCount++;
                requests.Push(storageUser.DownloadPointCloud(recordingKey, (success, list) =>
                {
                    if (success && list != null && list.Count > 0)
                    {
                        k_PointCloudRecorder.PointCloudEvents = list;
                        var dataRecording = k_PointCloudRecorder.TryCreateDataRecording(timeline, k_NewAssets);
                        if (dataRecording != null)
                        {
                            k_DataRecordings.Add(dataRecording);
                        }
                    }

                    resourceCount--;
                }));
            }

            while (resourceCount > 0)
            {
                yield return(null);
            }

            foreach (var dataRecording in k_DataRecordings)
            {
                recordingInfo.AddDataRecording(dataRecording);
                dataRecording.name = dataRecording.GetType().Name;
                AssetDatabase.AddObjectToAsset(dataRecording, timeline);
            }

            foreach (var newAsset in k_NewAssets)
            {
                AssetDatabase.AddObjectToAsset(newAsset, timeline);
            }

            AssetDatabase.SaveAssets();
            ProjectWindowUtil.ShowCreatedAsset(timeline);

            k_DataRecordings.Clear();
            k_NewAssets.Clear();

            if (!recording.HasVideo)
            {
                FinalizeDataRecordingImport(timeline, recordingKey, recordingPath, callback);
                yield break;
            }

            var videoPath = EditorUtility.SaveFilePanelInProject(k_SaveVideoDialogTitle, recordingName, k_VideoExtension, string.Empty);

            if (string.IsNullOrEmpty(recordingPath))
            {
                FinalizeDataRecordingImport(timeline, recordingKey, recordingPath, callback);
                yield break;
            }

            // TODO: Progress bar
            requests.Push(storageUser.DownloadVideo(recordingKey, (success, path) =>
            {
                try
                {
                    AssetDatabase.StartAssetEditing();

                    if (File.Exists(path))
                    {
                        var destinationPath = Path.Combine(Directory.GetCurrentDirectory(), videoPath);
                        if (File.Exists(destinationPath))
                        {
                            File.Delete(destinationPath);
                        }

                        File.Move(path, destinationPath);
                    }
                    else
                    {
                        Debug.LogError($"Couldn't find temp video file at path {path}");
                    }
                }
                catch (IOException e)
                {
                    Debug.LogException(e);
                }
                finally
                {
                    AssetDatabase.StopAssetEditing();
                }

                AssetDatabase.Refresh();

                var videoClip                      = AssetDatabase.LoadAssetAtPath <VideoClip>(videoPath);
                var videoTrack                     = timeline.CreateTrack <MarsVideoPlayableTrack>(null, k_DefaultVideoTrackName);
                var timelineClip                   = videoTrack.CreateClip <MarsVideoPlayableAsset>();
                timelineClip.displayName           = videoClip.name;
                timelineClip.duration              = videoClip.length;
                var videoPlayableAsset             = (MarsVideoPlayableAsset)timelineClip.asset;
                videoPlayableAsset.VideoClip       = videoClip;
                videoPlayableAsset.FacingDirection = CameraFacingDirection.World;
                timeline.editorSettings.fps        = (float)videoClip.frameRate;

                var videoHalfHeight            = videoClip.height * 0.5f;
                var halfFOV                    = recording.fovRadians * 0.5f;
                videoPlayableAsset.FocalLength = videoHalfHeight / Mathf.Tan(halfFOV);

                videoPlayableAsset.ZRotation = recording.zRotation;
            }));

            FinalizeDataRecordingImport(timeline, recordingKey, recordingPath, callback);
        }
        static RequestHandle ImportMarker(this IUsesCloudStorage storageUser, string imagePath, string markerKey,
                                          string jsonText, Action <UnityObject> callback)
        {
            return(storageUser.DownloadMarkerImage(markerKey, (success, tempPath) =>
            {
                var destinationPath = Path.Combine(Directory.GetCurrentDirectory(), imagePath);
                try
                {
                    AssetDatabase.StartAssetEditing();

                    if (File.Exists(tempPath))
                    {
                        if (File.Exists(destinationPath))
                        {
                            File.Delete(destinationPath);
                        }

                        File.Move(tempPath, destinationPath);
                    }
                    else
                    {
                        Debug.LogError($"Couldn't find image file at path {tempPath}");
                    }
                }
                catch (IOException e)
                {
                    Debug.LogException(e);
                }
                finally
                {
                    AssetDatabase.StopAssetEditing();
                }

                // we need access to the created texture for the image before we can add it to a marker library
                AssetDatabase.Refresh();

                ApplyImageMarkerTextureImportSettings(imagePath);

                var marker = SceneSerialization.FromJson <Marker>(jsonText);

                // add the created marker to a marker library
                var markerTex = AssetDatabase.LoadAssetAtPath <Texture2D>(imagePath);
                var markerLibrary = SelectMarkerLibrary();
                Guid markerGuid;
                if (markerTex != null && markerLibrary != null)
                {
                    markerGuid = CompanionEditorAssetUtils.CreateMarkerInLibrary(markerLibrary, marker, markerTex);
                }

                // create a Proxy in the scene with a MarkerCondition looking for the marker's new guid
                var markerProxyObj = CreateMarkerProxy(marker, markerGuid);
                EditorGUIUtility.PingObject(markerProxyObj);


                var prefabSavePath = EditorUtility.SaveFilePanelInProject(k_SaveProxyTitle,
                                                                          string.Format(k_ProxyNameFormat, marker.name), k_PrefabExtension, k_SaveProxyMessage);

                // if user presses 'cancel' in the save prompt, no prefab will be saved
                if (!string.IsNullOrEmpty(prefabSavePath))
                {
                    // creation of prefab is outside the start/stop editing block so we can highlight the created asset
                    var createdPrefab = PrefabUtility.SaveAsPrefabAssetAndConnect(markerProxyObj, prefabSavePath, InteractionMode.AutomatedAction);
                    ProjectWindowUtil.ShowCreatedAsset(createdPrefab);
                    callback(createdPrefab);
                }

                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();

                var resourceSync = CompanionResourceSync.instance;
                CompanionMarkerUtils.SplitMarkerKey(markerKey, out _, out var cloudGuid);
                resourceSync.SetAssetGuid(AssetDatabase.AssetPathToGUID(prefabSavePath), cloudGuid);
            }));
        }