/// <summary>
        /// Unload the specified bundle.
        /// </summary>
        /// <param name="bundleName">Name of the bundle.</param>
        /// <param name="objectDatabaseContentIndexMap">The object database asset index map, where newly loaded assets will be merged (ignored if null).</param>
        /// <returns></returns>
        public void UnloadBundle(string bundleName, ObjectDatabaseContentIndexMap objectDatabaseContentIndexMap)
        {
            lock (loadedBundles)
                lock (objects)
                {
                    // Unload package
                    UnloadBundleRecursive(bundleName, objectDatabaseContentIndexMap);

                    // Remerge previously loaded packages
                    foreach (var otherLoadedBundle in loadedBundles)
                    {
                        var bundle = otherLoadedBundle.Description;

                        // Read objects
                        foreach (var objectEntry in bundle.Objects)
                        {
                            objects[objectEntry.Key] = new ObjectLocation {
                                Info = objectEntry.Value, BundleUrl = otherLoadedBundle.BundleUrl
                            };
                        }

                        contentIndexMap.Merge(bundle.Assets);
                        objectDatabaseContentIndexMap.Merge(bundle.Assets);
                    }
                }
        }
        /// <summary>
        /// Loads the specified bundle.
        /// </summary>
        /// <param name="bundleName">Name of the bundle.</param>
        /// <param name="objectDatabaseContentIndexMap">The object database asset index map, where newly loaded assets will be merged (ignored if null).</param>
        /// <returns></returns>
        public async Task LoadBundle(string bundleName, ObjectDatabaseContentIndexMap objectDatabaseContentIndexMap)
        {
            if (bundleName == null)
            {
                throw new ArgumentNullException("bundleName");
            }

            // Check loaded bundles
            lock (loadedBundles)
            {
                foreach (var currentBundle in loadedBundles)
                {
                    if (currentBundle.BundleName == bundleName)
                    {
                        currentBundle.ReferenceCount++;
                        return;
                    }
                }
            }

            // Resolve package
            var vfsUrl = await ResolveBundle(bundleName, true);

            await LoadBundleFromUrl(bundleName, objectDatabaseContentIndexMap, vfsUrl);
        }
        public bool TestSingleUrl(PathSelector pathSelector, string asset)
        {
            var assetIndexMap = new ObjectDatabaseContentIndexMap();
            assetIndexMap[asset] = ObjectId.New();

            return pathSelector.Select(null, assetIndexMap).Count() == 1;
        }
Exemple #4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ObjectDatabase" /> class.
        /// </summary>
        /// <param name="vfsMainUrl">The VFS main URL.</param>
        /// <param name="indexName">Name of the index file.</param>
        /// <param name="vfsAdditionalUrl">The VFS additional URL. It will be used only if vfsMainUrl is read-only.</param>
        public ObjectDatabase(string vfsMainUrl, string indexName, string vfsAdditionalUrl = null, bool loadDefaultBundle = true)
        {
            if (vfsMainUrl == null)
            {
                throw new ArgumentNullException(nameof(vfsMainUrl));
            }

            // Create the merged asset index map
            ContentIndexMap = new ObjectDatabaseContentIndexMap();

            // Try to open file backends
            bool isReadOnly = Platform.Type != PlatformType.Windows;
            var  backend    = new FileOdbBackend(vfsMainUrl, indexName, isReadOnly);

            ContentIndexMap.Merge(backend.ContentIndexMap);
            if (backend.IsReadOnly)
            {
                backendRead1 = backend;
                if (vfsAdditionalUrl != null)
                {
                    backendWrite = backendRead2 = new FileOdbBackend(vfsAdditionalUrl, indexName, false);
                    ContentIndexMap.Merge(backendWrite.ContentIndexMap);
                }
            }
            else
            {
                backendWrite = backendRead1 = backend;
            }

            ContentIndexMap.WriteableContentIndexMap = backendWrite.ContentIndexMap;

            BundleBackend = new BundleOdbBackend(vfsMainUrl);

            // Try to open "default" pack file synchronously
            if (loadDefaultBundle)
            {
                try
                {
                    BundleBackend.LoadBundle("default", ContentIndexMap).GetAwaiter().GetResult();
                }
                catch (FileNotFoundException)
                {
                }
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ObjectDatabase" /> class.
        /// </summary>
        /// <param name="vfsMainUrl">The VFS main URL.</param>
        /// <param name="indexName">Name of the index file.</param>
        /// <param name="vfsAdditionalUrl">The VFS additional URL. It will be used only if vfsMainUrl is read-only.</param>
        public ObjectDatabase(string vfsMainUrl, string indexName, string vfsAdditionalUrl = null, bool loadDefaultBundle = true)
        {
            if (vfsMainUrl == null) throw new ArgumentNullException(nameof(vfsMainUrl));

            // Create the merged asset index map
            ContentIndexMap = new ObjectDatabaseContentIndexMap();

            // Try to open file backends
            bool isReadOnly = Platform.Type != PlatformType.Windows;
            var backend = new FileOdbBackend(vfsMainUrl, indexName, isReadOnly);

            ContentIndexMap.Merge(backend.ContentIndexMap);
            if (backend.IsReadOnly)
            {
                backendRead1 = backend;
                if (vfsAdditionalUrl != null)
                {
                    backendWrite = backendRead2 = new FileOdbBackend(vfsAdditionalUrl, indexName, false);
                    ContentIndexMap.Merge(backendWrite.ContentIndexMap);
                }
            }
            else
            {
                backendWrite = backendRead1 = backend;
            }

            ContentIndexMap.WriteableContentIndexMap = backendWrite.ContentIndexMap;

            BundleBackend = new BundleOdbBackend(vfsMainUrl);

            // Try to open "default" pack file synchronously
            if (loadDefaultBundle)
            {
                try
                {
                    BundleBackend.LoadBundle("default", ContentIndexMap).GetAwaiter().GetResult();
                }
                catch (FileNotFoundException)
                {
                }
            }
        }
        private void UnloadBundleRecursive(string bundleName, ObjectDatabaseContentIndexMap objectDatabaseContentIndexMap)
        {
            if (bundleName == null)
            {
                throw new ArgumentNullException("bundleName");
            }

            lock (loadedBundles)
            {
                int loadedBundleIndex = -1;

                for (int index = 0; index < loadedBundles.Count; index++)
                {
                    var currentBundle = loadedBundles[index];
                    if (currentBundle.BundleName == bundleName)
                    {
                        loadedBundleIndex = index;
                        break;
                    }
                }

                if (loadedBundleIndex == -1)
                {
                    throw new InvalidOperationException("Bundle has not been loaded.");
                }

                var loadedBundle = loadedBundles[loadedBundleIndex];
                var bundle       = loadedBundle.Description;
                if (--loadedBundle.ReferenceCount == 0)
                {
                    // Remove and dispose stream from pool
                    lock (bundleStreams)
                    {
                        Stream stream;
                        if (bundleStreams.TryGetValue(loadedBundle.BundleUrl, out stream))
                        {
                            bundleStreams.Remove(loadedBundle.BundleUrl);
                            stream.Dispose();
                        }
                    }

                    // Actually unload bundle
                    loadedBundles.RemoveAt(loadedBundleIndex);

                    // Unload objects from index map (if possible, replace with objects of other bundles
                    var removedObjects = new HashSet <ObjectId>();
                    foreach (var objectEntry in bundle.Objects)
                    {
                        objects.Remove(objectEntry.Key);
                        removedObjects.Add(objectEntry.Key);
                    }

                    // Unmerge with local (asset bundles) index map
                    contentIndexMap.Unmerge(bundle.Assets);

                    // Unmerge with global object database map
                    objectDatabaseContentIndexMap.Unmerge(bundle.Assets);

                    // Remove dependencies too
                    foreach (var dependency in bundle.Dependencies)
                    {
                        UnloadBundleRecursive(dependency, objectDatabaseContentIndexMap);
                    }
                }
            }
        }
        public async Task LoadBundleFromUrl(string bundleName, ObjectDatabaseContentIndexMap objectDatabaseContentIndexMap, string bundleUrl, bool ignoreDependencies = false)
        {
            BundleDescription bundle;

            using (var packStream = VirtualFileSystem.OpenStream(bundleUrl, VirtualFileMode.Open, VirtualFileAccess.Read))
            {
                bundle = ReadBundleDescription(packStream);
            }

            // Read and resolve dependencies
            if (!ignoreDependencies)
            {
                foreach (var dependency in bundle.Dependencies)
                {
                    await LoadBundle(dependency, objectDatabaseContentIndexMap);
                }
            }

            lock (loadedBundles)
            {
                LoadedBundle loadedBundle = null;

                foreach (var currentBundle in loadedBundles)
                {
                    if (currentBundle.BundleName == bundleName)
                    {
                        loadedBundle = currentBundle;
                        break;
                    }
                }

                if (loadedBundle == null)
                {
                    loadedBundle = new LoadedBundle
                    {
                        BundleName     = bundleName,
                        BundleUrl      = bundleUrl,
                        Description    = bundle,
                        ReferenceCount = 1
                    };

                    loadedBundles.Add(loadedBundle);
                }
                else
                {
                    loadedBundle.ReferenceCount++;
                }
            }

            // Read objects
            lock (objects)
            {
                foreach (var objectEntry in bundle.Objects)
                {
                    objects[objectEntry.Key] = new ObjectLocation {
                        Info = objectEntry.Value, BundleUrl = bundleUrl
                    };
                }
            }

            // Merge with local (asset bundles) index map
            contentIndexMap.Merge(bundle.Assets);

            // Merge with global object database map
            objectDatabaseContentIndexMap.Merge(bundle.Assets);
        }
Exemple #8
0
        public async Task LoadBundleFromUrl(string bundleName, ObjectDatabaseContentIndexMap objectDatabaseContentIndexMap, string bundleUrl, bool ignoreDependencies = false)
        {
            BundleDescription bundle = null;

            // If there is a .bundle, add incremental id before it
            var currentBundleExtensionUrl = bundleUrl.Length - (bundleUrl.EndsWith(BundleExtension) ? BundleExtension.Length : 0);

            // Process incremental bundles one by one
            using (var packStream = VirtualFileSystem.OpenStream(bundleUrl, VirtualFileMode.Open, VirtualFileAccess.Read))
            {
                bundle = ReadBundleDescription(packStream);
            }

            var files = new List <string> {
                bundleUrl
            };

            files.AddRange(bundle.IncrementalBundles.Select(x => bundleUrl.Insert(currentBundleExtensionUrl, "." + x)));

            if (bundle == null)
            {
                throw new FileNotFoundException("Could not find bundle", bundleUrl);
            }

            // Read and resolve dependencies
            if (!ignoreDependencies)
            {
                foreach (var dependency in bundle.Dependencies)
                {
                    await LoadBundle(dependency, objectDatabaseContentIndexMap);
                }
            }

            LoadedBundle loadedBundle = null;

            lock (loadedBundles)
            {
                foreach (var currentBundle in loadedBundles)
                {
                    if (currentBundle.BundleName == bundleName)
                    {
                        loadedBundle = currentBundle;
                        break;
                    }
                }

                if (loadedBundle == null)
                {
                    loadedBundle = new LoadedBundle
                    {
                        BundleName     = bundleName,
                        BundleUrl      = bundleUrl,
                        Description    = bundle,
                        ReferenceCount = 1,
                        Files          = files,
                        Streams        = new List <Stream>(files.Select(x => (Stream)null)),
                    };

                    loadedBundles.Add(loadedBundle);
                }
                else
                {
                    loadedBundle.ReferenceCount++;
                }
            }

            // Read objects
            lock (objects)
            {
                foreach (var objectEntry in bundle.Objects)
                {
                    objects[objectEntry.Key] = new ObjectLocation {
                        Info = objectEntry.Value, LoadedBundle = loadedBundle
                    };
                }
            }

            // Merge with local (asset bundles) index map
            contentIndexMap.Merge(bundle.Assets);

            // Merge with global object database map
            objectDatabaseContentIndexMap.Merge(bundle.Assets);
        }