Load content directories
Register a content directory at runtime and access its assets
읽는 시간 6분최근 업데이트: 16시간 전
Each call to populates the specified output directory with the built content from one or more root assets.
BuildPipeline.BuildContentDirectoryAt runtime, a script must call once per content directory to make its content available:
ContentLoadManager.RegisterContentDirectoryContentDirectoryHandle handle = ContentLoadManager.RegisterContentDirectory(localPath);
This loads the build manifest for the content directory to populate in-memory data structures. Root assets from the registered content directory become available through the APIs.
ContentLoadManagerAfter registering a content directory, you can call to discover what root assets are available inside it.
ContentLoadManager.GetRootAssetsGetRootAssets<T>TContentDirectoryHandleRegisterContentDirectoryWhen attempting to load an asset or scene, Unity searches through the loaded content directories in reverse order of their registration, meaning the last registered is the first searched, as in a stack.
Load content directories built outside the Assets folder
If you build content directories into , Unity imports every file that the content build produces. For a large content build, this wastes time and disk space each time Unity imports the project. To avoid this, build the content directories to a folder outside the folder and copy them into the Player build instead. The following example builds into .
Assets/StreamingAssetsAssetsBuilds/ContentDirectoriesThe example has two parts:
- A runtime helper class that registers content directories by name, in both Play mode and a Player build.
- An Editor build callback that copies the content directories into the Player build.
The following sections describe the runtime class first, then the Editor build callback that enables it in a Player. The Web platform needs extra handling in both parts. For more information, refer to Preload content directories for the Web platform.
Register content directories by name
The following class registers content directories by name and tracks their handles for cleanup. In Play mode it reads from the build output location. In a Player it reads from the folder, where the build callback copied them. On the Web platform, preloaded files are in the Emscripten virtual file system at .
StreamingAssets/vfs_streamingassets// Registers content directories by name and unregisters them on shutdown. public class ContentDirectoryManager { // Build output location for the content directories, relative to the // project folder. It's outside the Assets folder, so Unity doesn't // import the built content. public const string ContentBuildsPath = "Builds/ContentDirectories"; readonly List<ContentDirectoryHandle> m_Handles = new List<ContentDirectoryHandle>(); // During Play mode the content directories are read from the build // output location. In a Player they're read from the StreamingAssets // folder, where the Player build copied them. static string contentRootPath { get {#if UNITY_EDITOR return ContentBuildsPath;#elif UNITY_WEBGL // Preloaded StreamingAssets files are in the Emscripten virtual // file system at this fixed path. return "/vfs_streamingassets";#else return Application.streamingAssetsPath;#endif } } public void Register(string directoryName) { string path = contentRootPath + "/" + directoryName; m_Handles.Add(ContentLoadManager.RegisterContentDirectory(path)); } public void UnregisterAll() { for (int i = m_Handles.Count - 1; i >= 0; i--) { ContentLoadManager.UnregisterContentDirectory(m_Handles[i]); } m_Handles.Clear(); } }
Register each content directory by name from a bootstrap scene:
ContentDirectoryManager contentDirectories = new ContentDirectoryManager();contentDirectories.Register("MyContentDirectory");
Call on shutdown, after each asset is released and each scene from the content directories is unloaded.
UnregisterAllCopy the content directories into the Player build
BuildPlayerProcessor.PrepareForBuildBuildPlayerContext.AddAdditionalPathToStreamingAssetsStreamingAssets// Copies the built content directories into the Player build. class ContentDirectoryDeployment : BuildPlayerProcessor { // A Web build preloads the files listed by every manifest in this // folder into its virtual file system. const string k_WebPreloadFolder = "Library/PlayerDataCache/WebGLPreloadedStreamingAssets"; const string k_WebPreloadManifest = k_WebPreloadFolder + "/content-directories.manifest"; public override void PrepareForBuild( BuildPlayerContext buildPlayerContext) { string buildsPath = ContentDirectoryManager.ContentBuildsPath; // Skip if no content directories exist. This allows other builds // in the same project to proceed without content directories. if (!Directory.Exists(buildsPath)) return; string[] directories = Directory.GetDirectories(buildsPath); if (directories.Length == 0) return; // Unity copies the contents of buildsPath into the root of the // StreamingAssets folder, so each content directory keeps its own // folder name. buildPlayerContext.AddAdditionalPathToStreamingAssets(buildsPath); // Preserve the types used by the content so that managed code // stripping does not remove them. foreach (string directory in directories) { if (BuildHistory.TryGetBuildSummaryForOutputPath( directory, out BuildReportSummary summary)) { if (BuildHistory.TryGetBuildReportDirectory( summary.BuildSessionGUID, out string reportDirectory)) { buildPlayerContext.AddPreviousBuildReportDirectory( reportDirectory); } } } if (buildPlayerContext.BuildPlayerOptions.target == BuildTarget.WebGL) { WriteWebPreloadManifest(buildsPath, directories); } else if (File.Exists(k_WebPreloadManifest)) { // Remove the manifest from an earlier Web build, so that it // can't preload files in a later one. File.Delete(k_WebPreloadManifest); } } // The Web platform serves the StreamingAssets folder over HTTP, which // a browser can't read synchronously. RegisterContentDirectory needs // synchronous access, so list each file for the build to preload. static void WriteWebPreloadManifest(string buildsPath, string[] directories) { Directory.CreateDirectory(k_WebPreloadFolder); using (StreamWriter writer = new StreamWriter(k_WebPreloadManifest, false)) { foreach (string directory in directories) { string[] files = Directory.GetFiles( directory, "*", SearchOption.AllDirectories); string directoryName = Path.GetFileName(directory); foreach (string file in files) { string relativePath = directoryName + "/" + Path.GetRelativePath(directory, file); writer.WriteLine(relativePath.Replace('\\', '/')); } } } } }
Because copies the contents of the folder you pass it, each content directory keeps its own folder name at the root of . Build the content directories before you build the Player, so that the callback finds them.
AddAdditionalPathToStreamingAssetsStreamingAssetsThe example also looks up each content directory's build history folder using and passes it to , which preserves the types used by the content during managed code stripping. For more information, refer to How code stripping affects content.
BuildHistory.TryGetBuildSummaryForOutputPathAddPreviousBuildReportDirectoryPreload content directories for the Web platform
RegisterContentDirectoryStreamingAssetsTo select the files to preload, write a manifest file with the extension to , with one path per line relative to the folder. The build reads every manifest in that folder, so several packages can each contribute one. The method in the previous example lists every file in every content directory.
.manifestLibrary/PlayerDataCache/WebGLPreloadedStreamingAssetsStreamingAssetsWriteWebPreloadManifestWrite the manifest from , as the previous example does, so that the Player build finds it. A build callback that runs after the build, such as , is too late, because a Web build decides whether to pack each file into its virtual file system while it assembles the build.
PrepareForBuildIPostprocessBuildWithReportUnload a content directory
To clean up resources, call once per content directory after has been called on each loaded asset, and after each scene has been unloaded (for example, via ). Unity logs an error if is called while any files are open.
ContentLoadManager.UnregisterContentDirectoryLoadable.ReleaseSceneManager.UnloadSceneAsyncUnregisterContentDirectory