/// <summary> /// Unload the specified bundle. /// </summary> /// <param name="bundleName">Name of the bundle.</param> /// <param name="objectDatabaseAssetIndexMap">The object database asset index map, where newly loaded assets will be merged (ignored if null).</param> /// <returns></returns> public void UnloadBundle(string bundleName, ObjectDatabaseAssetIndexMap objectDatabaseAssetIndexMap) { lock (loadedBundles) lock (objects) { // Unload package UnloadBundleRecursive(bundleName, objectDatabaseAssetIndexMap); // 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 }; } assetIndexMap.Merge(bundle.Assets); objectDatabaseAssetIndexMap.Merge(bundle.Assets); } } }
/// <summary> /// Loads the specified bundle. /// </summary> /// <param name="bundleName">Name of the bundle.</param> /// <param name="objectDatabaseAssetIndexMap">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, ObjectDatabaseAssetIndexMap objectDatabaseAssetIndexMap) { 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, objectDatabaseAssetIndexMap, vfsUrl); }
public bool TestSingleUrl(PathSelector pathSelector, string asset) { var assetIndexMap = new ObjectDatabaseAssetIndexMap(); assetIndexMap[asset] = ObjectId.New(); return pathSelector.Select(null, assetIndexMap).Count() == 1; }
/// <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 = "index", string vfsAdditionalUrl = null, bool loadDefaultBundle = true) { if (vfsMainUrl == null) { throw new ArgumentNullException("vfsMainUrl"); } // Create the merged asset index map AssetIndexMap = new ObjectDatabaseAssetIndexMap(); // Try to open file backends bool isReadOnly = Platform.Type != PlatformType.Windows; var backend = new FileOdbBackend(vfsMainUrl, isReadOnly, indexName); AssetIndexMap.Merge(backend.AssetIndexMap); if (backend.IsReadOnly) { backendRead1 = backend; if (vfsAdditionalUrl != null) { backendWrite = backendRead2 = new FileOdbBackend(vfsAdditionalUrl, false); AssetIndexMap.Merge(backendWrite.AssetIndexMap); } } else { backendWrite = backendRead1 = backend; } AssetIndexMap.WriteableAssetIndexMap = backendWrite.AssetIndexMap; bundleBackend = new BundleOdbBackend(vfsMainUrl); // Try to open "default" pack file synchronously if (loadDefaultBundle) { try { bundleBackend.LoadBundle("default", AssetIndexMap).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 = "index", string vfsAdditionalUrl = null, bool loadDefaultBundle = true) { if (vfsMainUrl == null) throw new ArgumentNullException("vfsMainUrl"); // Create the merged asset index map AssetIndexMap = new ObjectDatabaseAssetIndexMap(); // Try to open file backends bool isReadOnly = Platform.Type != PlatformType.Windows; var backend = new FileOdbBackend(vfsMainUrl, isReadOnly, indexName); AssetIndexMap.Merge(backend.AssetIndexMap); if (backend.IsReadOnly) { backendRead1 = backend; if (vfsAdditionalUrl != null) { backendWrite = backendRead2 = new FileOdbBackend(vfsAdditionalUrl, false); AssetIndexMap.Merge(backendWrite.AssetIndexMap); } } else { backendWrite = backendRead1 = backend; } AssetIndexMap.WriteableAssetIndexMap = backendWrite.AssetIndexMap; bundleBackend = new BundleOdbBackend(vfsMainUrl); // Try to open "default" pack file synchronously if (loadDefaultBundle) { try { bundleBackend.LoadBundle("default", AssetIndexMap).GetAwaiter().GetResult(); } catch (FileNotFoundException) { } } }
private void UnloadBundleRecursive(string bundleName, ObjectDatabaseAssetIndexMap objectDatabaseAssetIndexMap) { 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 assetIndexMap.Unmerge(bundle.Assets); // Unmerge with global object database map objectDatabaseAssetIndexMap.Unmerge(bundle.Assets); // Remove dependencies too foreach (var dependency in bundle.Dependencies) { UnloadBundleRecursive(dependency, objectDatabaseAssetIndexMap); } } } }
public async Task LoadBundleFromUrl(string bundleName, ObjectDatabaseAssetIndexMap objectDatabaseAssetIndexMap, 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, objectDatabaseAssetIndexMap); } } 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 assetIndexMap.Merge(bundle.Assets); // Merge with global object database map objectDatabaseAssetIndexMap.Merge(bundle.Assets); }
/// <summary> /// Loads the specified bundle. /// </summary> /// <param name="bundleName">Name of the bundle.</param> /// <param name="objectDatabaseAssetIndexMap">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, ObjectDatabaseAssetIndexMap objectDatabaseAssetIndexMap) { 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); BundleDescription bundle; using (var packStream = VirtualFileSystem.OpenStream(vfsUrl, VirtualFileMode.Open, VirtualFileAccess.Read)) { bundle = ReadBundleDescription(packStream); } // Read and resolve dependencies foreach (var dependency in bundle.Dependencies) { await LoadBundle(dependency, objectDatabaseAssetIndexMap); } 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 = vfsUrl, 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 = vfsUrl }; } } // Merge with local (asset bundles) index map assetIndexMap.Merge(bundle.Assets); // Merge with global object database map objectDatabaseAssetIndexMap.Merge(bundle.Assets); }