public CacheEntry(Guid id, Guid containerId, AssetSource source, Object asset)
 {
     Id          = id;
     ContainerId = containerId;
     Source      = source;
     Asset       = asset;
 }
示例#2
0
 public CacheEntry(Guid id, Guid containerId, AssetSource source, Object asset, ColliderGeometry collider = null)
 {
     Id               = id;
     ContainerId      = containerId;
     Source           = source;
     Asset            = asset;
     ColliderGeometry = collider;
 }
示例#3
0
 public AssetMetadata(Guid id, Guid containerId, Object asset,
                      ColliderGeometry collider = null, AssetSource source = null)
 {
     Id               = id;
     ContainerId      = containerId;
     Source           = source;
     Asset            = asset;
     ColliderGeometry = collider;
 }
        /// <inheritdoc cref="GetAssetIdsInSource"/>
        public IEnumerable<Guid> GetAssetIdsInSource(AssetSource source = null)
        {
            List<Guid> guids;

            if (source != null)
            {
                assetsBySource.TryGetValue(source, out guids);
            }
            else
            {
                guids = manualAssets;
            }

            return guids;
        }
        /// <inheritdoc cref="CacheAsset"/>
        public void CacheAsset(Object asset, Guid id, AssetSource source = null)
        {
            List<Guid> assetList;
            if(source != null)
            {
                assetList = assetsBySource.GetOrCreate(source, () => new List<Guid>(ASSET_DEFAULT_COUNT));
            }
            else
            {
                assetList = manualAssets;
            }

            assetList.Add(id);
            assets[id] = asset;
            ids[asset] = id;
        }
示例#6
0
        /// <inheritdoc cref="CacheAsset"/>
        public void CacheAsset(Object asset, Guid id, Guid containerId, AssetSource source = null, ColliderGeometry colliderGeo = null)
        {
            if (!cache.Any(c => c.Id == id))
            {
                cache.Add(new CacheEntry(id, containerId, source, asset, colliderGeo));
            }

            if (cacheCallbacks.TryGetValue(id, out List <CacheCallback> callbacks))
            {
                cacheCallbacks.Remove(id);
                foreach (var cb in callbacks)
                {
                    try
                    {
                        cb?.Invoke(asset);
                    }
                    catch (Exception e)
                    {
                        Debug.LogException(e);
                    }
                }
            }
        }
        /// <summary>
        /// Track a new asset reference. Will be called during asset creation, after the asset content is downloaded
        /// or retrieved from cache.
        /// </summary>
        /// <param name="id"></param>
        /// <param name="containerId"></param>
        /// <param name="asset"></param>
        /// <param name="colliderGeo"></param>
        /// <param name="source"></param>
        public void Set(Guid id, Guid containerId, Object asset,
                        ColliderGeometry colliderGeo = null, AssetSource source = null)
        {
            if (!Assets.ContainsKey(id))
            {
                Assets[id] = new AssetMetadata(id, containerId, asset, colliderGeo, source);
            }

            if (Callbacks.TryGetValue(id, out List <AssetCallback> callbacks))
            {
                Callbacks.Remove(id);
                foreach (var cb in callbacks)
                {
                    try
                    {
                        cb?.Invoke(Assets[id]);
                    }
                    catch (Exception e)
                    {
                        Debug.LogException(e);
                    }
                }
            }
        }
示例#8
0
        internal async void OnCreateAsset(CreateAsset payload, Action onCompleteCallback)
        {
            var def        = payload.Definition;
            var response   = new AssetsLoaded();
            var unityAsset = _app.AssetManager.GetById(def.Id)?.Asset;
            ColliderGeometry colliderGeo = null;
            AssetSource      source      = null;

            ActiveContainers.Add(payload.ContainerId);

            // create materials
            if (unityAsset == null && def.Material != null)
            {
                unityAsset = UnityEngine.Object.Instantiate(MREAPI.AppsAPI.DefaultMaterial);
            }

            // create textures
            else if (unityAsset == null && def.Texture != null)
            {
                var texUri = new Uri(_app.ServerAssetUri, def.Texture.Value.Uri);
                source = new AssetSource(AssetContainerType.None, texUri.AbsoluteUri);
                var result = await AssetFetcher <UnityEngine.Texture> .LoadTask(_owner, texUri);

                // this is a newly loaded texture, so we decide initial settings for the shared asset
                if (result.ReturnCode == 200)
                {
                    result.Asset.wrapModeU = def.Texture.Value.WrapModeU ?? TextureWrapMode.Repeat;
                    result.Asset.wrapModeV = def.Texture.Value.WrapModeV ?? TextureWrapMode.Repeat;
                }

                unityAsset     = result.Asset;
                source.Version = result.ETag;
                if (result.FailureMessage != null)
                {
                    response.FailureMessage = result.FailureMessage;
                }
            }

            // create meshes
            else if (unityAsset == null && def.Mesh != null)
            {
                if (def.Mesh.Value.PrimitiveDefinition != null)
                {
                    var factory = MREAPI.AppsAPI.PrimitiveFactory;
                    try
                    {
                        unityAsset  = factory.CreatePrimitive(def.Mesh.Value.PrimitiveDefinition.Value);
                        colliderGeo = ConvertPrimToCollider(def.Mesh.Value.PrimitiveDefinition.Value, def.Id);
                    }
                    catch (Exception e)
                    {
                        response.FailureMessage = e.Message;
                        MREAPI.Logger.LogError(response.FailureMessage);
                    }
                }
                else
                {
                    response.FailureMessage = $"Cannot create mesh {def.Id} without a primitive definition";
                }
            }

            // create sounds
            else if (unityAsset == null && def.Sound != null)
            {
                var soundUri = new Uri(_app.ServerAssetUri, def.Sound.Value.Uri);
                source = new AssetSource(AssetContainerType.None, soundUri.AbsoluteUri);
                var result = await AssetFetcher <UnityEngine.AudioClip> .LoadTask(_owner, soundUri);

                unityAsset     = result.Asset;
                source.Version = result.ETag;
                if (result.FailureMessage != null)
                {
                    response.FailureMessage = result.FailureMessage;
                }
            }

            // create video streams
            else if (unityAsset == null && def.VideoStream != null)
            {
                if (MREAPI.AppsAPI.VideoPlayerFactory != null)
                {
                    string videoString;

                    // These youtube "URIs" are not valid URIs because they are case-sensitive. Don't parse, and
                    // deprecate this URL scheme as soon as feasible.
                    if (def.VideoStream.Value.Uri.StartsWith("youtube://"))
                    {
                        videoString = def.VideoStream.Value.Uri;
                    }
                    else
                    {
                        var videoUri = new Uri(_app.ServerAssetUri, def.VideoStream.Value.Uri);
                        videoString = videoUri.AbsoluteUri;
                    }

                    PluginInterfaces.FetchResult result2 = MREAPI.AppsAPI.VideoPlayerFactory.PreloadVideoAsset(videoString);
                    unityAsset = result2.Asset;
                    if (result2.FailureMessage != null)
                    {
                        response.FailureMessage = result2.FailureMessage;
                    }
                }
                else
                {
                    response.FailureMessage = "VideoPlayerFactory not implemented";
                }
            }

            // create animation data
            else if (unityAsset == null && def.AnimationData != null)
            {
                var animDataCache = ScriptableObject.CreateInstance <AnimationDataCached>();
                animDataCache.Tracks = def.AnimationData.Value.Tracks;
                unityAsset           = animDataCache;
            }

            _app.AssetManager.Set(def.Id, payload.ContainerId, unityAsset, colliderGeo, source);

            // verify creation and apply initial patch
            if (unityAsset != null)
            {
                unityAsset.name = def.Name;
                OnAssetUpdate(new AssetUpdate()
                {
                    Asset = def
                }, null);

                try
                {
                    response.Assets = new Asset[] { GenerateAssetPatch(unityAsset, def.Id) };
                }
                catch (Exception e)
                {
                    response.FailureMessage = e.Message;
                    _app.Logger.LogError(response.FailureMessage);
                }
            }
            else
            {
                if (response.FailureMessage == null)
                {
                    response.FailureMessage = $"Not implemented: CreateAsset of new asset type";
                }
                _app.Logger.LogError(response.FailureMessage);
            }

            _app.Protocol.Send(new Message()
            {
                ReplyToId = payload.MessageId,
                Payload   = response
            });

            onCompleteCallback?.Invoke();
        }
示例#9
0
        private async Task <IList <Asset> > LoadAssetsFromGLTF(AssetSource source, Guid containerId, ColliderType colliderType)
        {
            WebRequestLoader loader = null;
            Stream           stream = null;

            source.ParsedUri = new Uri(_app.ServerAssetUri, source.ParsedUri);
            var rootUri       = URIHelper.GetDirectoryName(source.ParsedUri.AbsoluteUri);
            var cachedVersion = MREAPI.AppsAPI.AssetCache.SupportsSync ?
                                MREAPI.AppsAPI.AssetCache.GetVersionSync(source.ParsedUri) :
                                await MREAPI.AppsAPI.AssetCache.GetVersion(source.ParsedUri);

            // Wait asynchronously until the load throttler lets us through.
            using (var scope = await AssetLoadThrottling.AcquireLoadScope())
            {
                // set up loader
                loader = new WebRequestLoader(rootUri);
                if (!string.IsNullOrEmpty(cachedVersion))
                {
                    loader.BeforeRequestCallback += (msg) =>
                    {
                        if (msg.RequestUri == source.ParsedUri)
                        {
                            msg.Headers.Add("If-None-Match", cachedVersion);
                        }
                    };
                }

                // download root gltf file, check for cache hit
                try
                {
                    stream = await loader.LoadStreamAsync(URIHelper.GetFileFromUri(source.ParsedUri));

                    source.Version = loader.LastResponse.Headers.ETag?.Tag ?? "";
                }
                catch (HttpRequestException)
                {
                    if (loader.LastResponse.StatusCode == System.Net.HttpStatusCode.NotModified)
                    {
                        source.Version = cachedVersion;
                    }
                    else
                    {
                        throw;
                    }
                }
            }

            IList <Asset>      assetDefs     = new List <Asset>(30);
            DeterministicGuids guidGenerator = new DeterministicGuids(UtilMethods.StringToGuid(
                                                                          $"{containerId}:{source.ParsedUri.AbsoluteUri}"));
            IList <UnityEngine.Object> assets;

            // fetch assets from glTF stream or cache
            if (source.Version != cachedVersion)
            {
                assets = await LoadGltfFromStream(loader, stream, colliderType);

                MREAPI.AppsAPI.AssetCache.StoreAssets(source.ParsedUri, assets, source.Version);
            }
            else
            {
                var assetsEnum = MREAPI.AppsAPI.AssetCache.SupportsSync ?
                                 MREAPI.AppsAPI.AssetCache.LeaseAssetsSync(source.ParsedUri) :
                                 await MREAPI.AppsAPI.AssetCache.LeaseAssets(source.ParsedUri);

                assets = assetsEnum.ToList();
            }

            // catalog assets
            int textureIndex = 0, meshIndex = 0, materialIndex = 0, prefabIndex = 0;

            foreach (var asset in assets)
            {
                var assetDef = GenerateAssetPatch(asset, guidGenerator.Next());
                assetDef.Name = asset.name;

                string internalId = null;
                if (asset is UnityEngine.Texture)
                {
                    internalId = $"texture:{textureIndex++}";
                }
                else if (asset is UnityEngine.Mesh)
                {
                    internalId = $"mesh:{meshIndex++}";
                }
                else if (asset is UnityEngine.Material)
                {
                    internalId = $"material:{materialIndex++}";
                }
                else if (asset is GameObject)
                {
                    internalId = $"scene:{prefabIndex++}";
                }
                assetDef.Source = new AssetSource(source.ContainerType, source.ParsedUri.AbsoluteUri, internalId, source.Version);

                ColliderGeometry colliderGeo = null;
                if (asset is UnityEngine.Mesh mesh)
                {
                    colliderGeo = colliderType == ColliderType.Mesh ?
                                  (ColliderGeometry) new MeshColliderGeometry()
                    {
                        MeshId = assetDef.Id
                    } :
                    (ColliderGeometry) new BoxColliderGeometry()
                    {
                        Size   = (mesh.bounds.size * 0.8f).CreateMWVector3(),
                        Center = mesh.bounds.center.CreateMWVector3()
                    };
                }

                _app.AssetManager.Set(assetDef.Id, containerId, asset, colliderGeo, assetDef.Source);
                assetDefs.Add(assetDef);
            }

            return(assetDefs);
        }
        private async Task <IList <Asset> > LoadAssetsFromGLTF(AssetSource source, Guid containerId, ColliderType colliderType)
        {
            IList <Asset>      assets        = new List <Asset>();
            DeterministicGuids guidGenerator = new DeterministicGuids(UtilMethods.StringToGuid(
                                                                          $"{containerId}:{source.ParsedUri.AbsoluteUri}"));

            // download file
            UtilMethods.GetUrlParts(source.ParsedUri.AbsoluteUri, out string rootUrl, out string filename);
            var loader = new WebRequestLoader(rootUrl);
            await loader.LoadStream(filename);

            // pre-parse glTF document so we can get a scene count
            // TODO: run this in thread
            GLTF.GLTFParser.ParseJson(loader.LoadedStream, out GLTF.Schema.GLTFRoot gltfRoot);

            GLTFSceneImporter importer =
                MREAPI.AppsAPI.GLTFImporterFactory.CreateImporter(gltfRoot, loader, _asyncHelper, loader.LoadedStream);

            importer.SceneParent = MREAPI.AppsAPI.AssetCache.CacheRootGO().transform;
            importer.Collider    = colliderType.ToGLTFColliderType();

            // load prefabs
            if (gltfRoot.Scenes != null)
            {
                for (var i = 0; i < gltfRoot.Scenes.Count; i++)
                {
                    await importer.LoadSceneAsync(i);

                    GameObject rootObject = importer.LastLoadedScene;
                    rootObject.name = gltfRoot.Scenes[i].Name ?? $"scene:{i}";
                    MWGOTreeWalker.VisitTree(rootObject, (go) =>
                    {
                        go.layer = UnityConstants.ActorLayerIndex;
                    });

                    var def = GenerateAssetPatch(rootObject, guidGenerator.Next());
                    def.Name   = rootObject.name;
                    def.Source = new AssetSource(source.ContainerType, source.Uri, $"scene:{i}");
                    MREAPI.AppsAPI.AssetCache.CacheAsset(rootObject, def.Id, containerId, source);
                    assets.Add(def);
                }
            }

            // load textures
            if (gltfRoot.Textures != null)
            {
                for (var i = 0; i < gltfRoot.Textures.Count; i++)
                {
                    await importer.LoadTextureAsync(gltfRoot.Textures[i], i, true);

                    var texture = importer.GetTexture(i);
                    texture.name = gltfRoot.Textures[i].Name ?? $"texture:{i}";

                    var asset = GenerateAssetPatch(texture, guidGenerator.Next());
                    asset.Name   = texture.name;
                    asset.Source = new AssetSource(source.ContainerType, source.Uri, $"texture:{i}");
                    MREAPI.AppsAPI.AssetCache.CacheAsset(texture, asset.Id, containerId, source);
                    assets.Add(asset);
                }
            }

            // load materials
            if (gltfRoot.Materials != null)
            {
                for (var i = 0; i < gltfRoot.Materials.Count; i++)
                {
                    var matdef   = gltfRoot.Materials[i];
                    var material = await importer.LoadMaterialAsync(i);

                    material.name = matdef.Name ?? $"material:{i}";

                    var asset = GenerateAssetPatch(material, guidGenerator.Next());
                    asset.Name   = material.name;
                    asset.Source = new AssetSource(source.ContainerType, source.Uri, $"material:{i}");
                    MREAPI.AppsAPI.AssetCache.CacheAsset(material, asset.Id, containerId, source);
                    assets.Add(asset);
                }
            }

            importer.Dispose();

            return(assets);
        }
示例#11
0
        private async Task <IList <Asset> > LoadAssetsFromGLTF(AssetSource source, Guid containerId, ColliderType colliderType)
        {
            IList <Asset>      assets        = new List <Asset>();
            DeterministicGuids guidGenerator = new DeterministicGuids(UtilMethods.StringToGuid(
                                                                          $"{containerId}:{source.ParsedUri.AbsoluteUri}"));

            // download file
            var rootUrl = URIHelper.GetDirectoryName(source.ParsedUri.AbsoluteUri);
            var loader  = new WebRequestLoader(rootUrl);
            var stream  = await loader.LoadStreamAsync(URIHelper.GetFileFromUri(source.ParsedUri));

            // pre-parse glTF document so we can get a scene count
            // TODO: run this in thread
            GLTF.GLTFParser.ParseJson(stream, out GLTF.Schema.GLTFRoot gltfRoot);
            stream.Position = 0;

            GLTFSceneImporter importer =
                MREAPI.AppsAPI.GLTFImporterFactory.CreateImporter(gltfRoot, loader, _asyncHelper, stream);

            importer.SceneParent = MREAPI.AppsAPI.AssetCache.CacheRootGO().transform;
            importer.Collider    = colliderType.ToGLTFColliderType();

            // load textures
            if (gltfRoot.Textures != null)
            {
                for (var i = 0; i < gltfRoot.Textures.Count; i++)
                {
                    await importer.LoadTextureAsync(gltfRoot.Textures[i], i, true);

                    var texture = importer.GetTexture(i);
                    texture.name = gltfRoot.Textures[i].Name ?? $"texture:{i}";

                    var asset = GenerateAssetPatch(texture, guidGenerator.Next());
                    asset.Name   = texture.name;
                    asset.Source = new AssetSource(source.ContainerType, source.Uri, $"texture:{i}");
                    MREAPI.AppsAPI.AssetCache.CacheAsset(texture, asset.Id, containerId, source);
                    assets.Add(asset);
                }
            }

            // load meshes
            if (gltfRoot.Meshes != null)
            {
                var cancellationSource = new System.Threading.CancellationTokenSource();
                for (var i = 0; i < gltfRoot.Meshes.Count; i++)
                {
                    var mesh = await importer.LoadMeshAsync(i, cancellationSource.Token);

                    mesh.name = gltfRoot.Meshes[i].Name ?? $"mesh:{i}";

                    var asset = GenerateAssetPatch(mesh, guidGenerator.Next());
                    asset.Name   = mesh.name;
                    asset.Source = new AssetSource(source.ContainerType, source.Uri, $"mesh:{i}");
                    var colliderGeo = colliderType == ColliderType.Mesh ?
                                      (ColliderGeometry) new MeshColliderGeometry()
                    {
                        MeshId = asset.Id
                    } :
                    (ColliderGeometry) new BoxColliderGeometry()
                    {
                        Size = (mesh.bounds.size * 0.8f).CreateMWVector3()
                    };
                    MREAPI.AppsAPI.AssetCache.CacheAsset(mesh, asset.Id, containerId, source, colliderGeo);
                    assets.Add(asset);
                }
            }

            // load materials
            if (gltfRoot.Materials != null)
            {
                for (var i = 0; i < gltfRoot.Materials.Count; i++)
                {
                    var matdef   = gltfRoot.Materials[i];
                    var material = await importer.LoadMaterialAsync(i);

                    material.name = matdef.Name ?? $"material:{i}";

                    var asset = GenerateAssetPatch(material, guidGenerator.Next());
                    asset.Name   = material.name;
                    asset.Source = new AssetSource(source.ContainerType, source.Uri, $"material:{i}");
                    MREAPI.AppsAPI.AssetCache.CacheAsset(material, asset.Id, containerId, source);
                    assets.Add(asset);
                }
            }

            // load prefabs
            if (gltfRoot.Scenes != null)
            {
                for (var i = 0; i < gltfRoot.Scenes.Count; i++)
                {
                    await importer.LoadSceneAsync(i).ConfigureAwait(true);

                    GameObject rootObject = importer.LastLoadedScene;
                    rootObject.name = gltfRoot.Scenes[i].Name ?? $"scene:{i}";

                    var animation = rootObject.GetComponent <UnityEngine.Animation>();
                    if (animation != null)
                    {
                        animation.playAutomatically = false;

                        // initialize mapping so we know which gameobjects are targeted by which animation clips
                        var mapping = rootObject.AddComponent <PrefabAnimationTargets>();
                        mapping.Initialize(gltfRoot, i);
                    }

                    MWGOTreeWalker.VisitTree(rootObject, (go) =>
                    {
                        go.layer = MREAPI.AppsAPI.LayerApplicator.DefaultLayer;
                    });

                    var def = GenerateAssetPatch(rootObject, guidGenerator.Next());
                    def.Name   = rootObject.name;
                    def.Source = new AssetSource(source.ContainerType, source.Uri, $"scene:{i}");
                    MREAPI.AppsAPI.AssetCache.CacheAsset(rootObject, def.Id, containerId, source);
                    assets.Add(def);
                }
            }

            importer.Dispose();

            return(assets);
        }