Skip to content

Commit ea63707

Browse files
[#97] Add Unity scenes to LeadingEdge reference builds and improve docs (#98)
* [#97] Add Unity scenes to LeadingEdge reference builds (AssetBundle and content directory) Document built-in resource handling for Player, AssetBundle and content directory builds. Explain built-in resource dangling refs in test and docs. Flesh out detail on how they are handled based on research into the code.
1 parent d930e40 commit ea63707

45 files changed

Lines changed: 1309 additions & 250 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Documentation/assetbundle-format.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,42 @@ In UnityDataTool output, these layers appear in different places:
9191
Keeping those layers separate helps explain why a query over `refs` may show cross-bundle
9292
relationships without directly mentioning an AssetBundle filename on each reference row.
9393

94+
## Built-in resources
95+
96+
Bundle content can reference objects in Unity's two built-in resource files (described in
97+
[Built-in resource files](playerbuild-format.md#built-in-resource-files) on the Player build page).
98+
`BuildPipeline.BuildAssetBundles` handles the two differently:
99+
100+
- References to **`Library/unity default resources`** objects (default meshes, the RenderSettings
101+
spot cookie, and so on) always stay external references. This is safe: that file is identical in
102+
every Player of the same Unity version, so the referenced objects are always available at runtime.
103+
- Objects from **`Resources/unity_builtin_extra`** (built-in shaders and materials) are treated like
104+
user assets and copied into the bundle that uses them — with one exception: shaders in the
105+
project's **Always Included Shaders** list (Graphics Settings) are not copied, but referenced
106+
externally from `Resources/unity_builtin_extra`. A Player build writes exactly those shaders into
107+
its copy of that file, so the references resolve when the bundles and the Player are built from
108+
the same project settings.
109+
110+
For example, in the reference scene bundle in `TestCommon/Data/LeadingEdgeBuilds/AssetBundles`, the
111+
`Sprites-Default` Material and the default reflection Cubemap are copied into the bundle's
112+
`.sharedAssets` file, but the material's `Sprites/Default` *shader* stays an external reference into
113+
`Resources/unity_builtin_extra`, because that shader is in the default Always Included Shaders list.
114+
115+
Those external shader references couple a bundle to the Player that loads it: if the Player was
116+
built with a different Always Included Shaders list (a different project, or settings that changed
117+
between builds), the bundle can reference a shader the Player does not contain. When you run
118+
[`analyze`](command-analyze.md) on bundles, references into either built-in file show up in
119+
`dangling_refs_view`, because the built-in files themselves are never part of the bundle build
120+
output.
121+
122+
The Scriptable Build Pipeline avoids the coupling entirely: it never references the Player's
123+
`unity_builtin_extra`, and instead copies the referenced built-in objects into each bundle that uses
124+
them (references to `unity default resources` stay external, as above). The cost is duplication when
125+
several bundles use the same built-in shader; the optional `CreateBuiltInBundle` build task removes
126+
that by collecting the built-in objects into a single dedicated bundle. The Addressables package
127+
enables that task in its default build, so Addressables content contains its own copy of the
128+
built-in shaders it needs and does not depend on the Player's Always Included Shaders list.
129+
94130
## Inspecting a bundle with UnityDataTool
95131

96132
The [`archive`](command-archive.md) command lists or extracts the files inside a bundle, and

Documentation/contentdirectory-format.md

Lines changed: 98 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ runtime.
5252

5353
Every build artifact is named by the hash of its own content:
5454

55-
- **Content Files** use the `.cf` extension (for example `a77f98db89b6aa1aeaaad01d857e5115.cf`).
55+
- **Content Files** use the `.cf` extension (for example `c0152db4dd710be51b2decb997325f34.cf`).
5656
- **`.resS`** files hold streamed texture and mesh data.
5757
- **`.resource`** files hold audio and video data.
5858

@@ -73,7 +73,7 @@ are present both for loose files and for entries packed inside an archive.
7373
### The build manifest
7474

7575
The build manifest is a JSON file, also named by its content hash (for example
76-
`15d5df98d98434e67e06716cfabfad1b.json`). It records everything needed to load the content: the list of
76+
`baff06b928d147276f2245dd3b19216a.json`). It records everything needed to load the content: the list of
7777
Content Files, their dependencies, and the loadable objects and scenes. Its schema is internal and may
7878
change substantially, so this page does not document it. Instead, use
7979
[`ContentLayout.json`](contentlayout.md), which presents the same information (plus source-asset
@@ -106,7 +106,7 @@ many files contain just a single Unity object (a Material, Shader, Texture, Audi
106106
few grouping rules shape the result:
107107

108108
- **Scenes and Prefabs** store their whole GameObject/Component hierarchy together in a single Content
109-
File, just as they are represented in the Editor.
109+
File, just as they are represented in the Editor (see [Scenes](#scenes) below).
110110
- **Assets with sub-assets** are split across multiple Content Files. For example an FBX is separated
111111
so that the component hierarchy and the meshes land in different files.
112112
- **Scripts** are grouped: the `MonoScript` objects for several source scripts can share one Content
@@ -116,10 +116,84 @@ few grouping rules shape the result:
116116
to break a cycle is to convert one of the references into a `Loadable` (an on-demand reference)
117117
instead of a direct reference.
118118

119-
Built-in resources are handled specially. The manifest carries an entry for `unity default resources`
120-
flagged as built-in (with no content hash); references to it resolve through the runtime's built-in
121-
resource mechanism and the `PersistentManager`, rather than through the `ContentLoadManager` that
122-
manages Content Files.
119+
Unity's two built-in resource files are handled in different ways:
120+
121+
- **`unity default resources`** is referenced but not included in the build, because those resources
122+
are always present in the Player that loads the content directory. The manifest carries an entry
123+
for it flagged as built-in (with no content hash); references to it resolve through the runtime's
124+
built-in resource mechanism and the `PersistentManager`, rather than through the
125+
`ContentLoadManager` that manages Content Files.
126+
- **`Resources/unity_builtin_extra`** gets no such special treatment: any referenced objects from it
127+
(for example the default sprite material and its shader) are included directly in the content
128+
directory output, in a Content File named by its content hash just like any other file in the
129+
build. This is because the `unity_builtin_extra` file in a Player is generated per build and
130+
contains only the project's "Always Included Shaders" — copying the referenced objects into the
131+
content directory makes it independent of what a particular Player build happens to contain.
132+
133+
## Scenes
134+
135+
Content directory builds can include Unity Scenes. The build parameters only accept ScriptableObject
136+
assets as roots, so a scene enters the build by being referenced through a `LoadableSceneId` field (a
137+
small serializable struct identifying the scene) on an asset reachable from the roots. Every scene
138+
referenced this way is added to the output, along with the assets the scene itself references. At
139+
runtime, such a scene is loaded with `SceneManager.LoadSceneAsync(LoadableSceneId)` once the content
140+
directory is registered.
141+
142+
Each scene produces exactly one Content File, containing only the scene's own GameObject/Component
143+
hierarchy and scene settings objects. The assets the scene references (textures, materials, and so
144+
on) are not packed with it — they land in their own Content Files following the normal
145+
[granularity rules](#build-layout-granularity), and the scene's file reaches them through the
146+
manifest dependency list. This differs from Player builds, where each scene comes with companion
147+
`sharedassets` files holding its assets. Scene Content Files also differ in their object IDs: the
148+
scene's objects get small sequential IDs (1, 2, 3, ...), rather than the 64-bit hash-based IDs used
149+
in other Content Files.
150+
151+
In `ContentLayout.json` (schema details on the [ContentLayout.json](contentlayout.md) page), the
152+
top-level `LoadableSceneIds` array lists each scene with its source path and the Content File that
153+
holds it. From the reference build in `TestCommon/Data/LeadingEdgeBuilds`, which includes two small
154+
scenes:
155+
156+
```json
157+
"LoadableSceneIds": [
158+
{ "GUID": "590cfeb4e0ff90f4e92f9e1262bcfe6f", "Path": "Assets/Scenes/Scene2.unity", "SerializedFile": 6 },
159+
{ "GUID": "162c015549f8733449ac70ae78ad3aa5", "Path": "Assets/Scenes/Scene1.unity", "SerializedFile": 2 }
160+
]
161+
```
162+
163+
The scene's own `SerializedFiles` entry names the scene as its single source asset, and its symbolic
164+
`ID` is derived from the scene's GUID:
165+
166+
```json
167+
{
168+
"Index": 2,
169+
"ID": "162c015549f8733449ac70ae78ad3aa5.cfid",
170+
"SourceAssets": [ "Assets/Scenes/Scene1.unity" ],
171+
"SerializedFileDependencies": [ 0, 1, 9 ],
172+
"ContentHash": "c271b85494f5e4cc35c4ec4a776324af"
173+
}
174+
```
175+
176+
So this scene lives in `c271b85494f5e4cc35c4ec4a776324af.cf`, and depends on three other files: the
177+
built-in `unity default resources` entry, the Content File built from `Resources/unity_builtin_extra`
178+
(the default sprite material), and the file holding the Sprite it shows.
179+
180+
A `LoadableSceneId` reference is an on-demand reference, like a `Loadable`: loading the referencing
181+
file does not load the scene. The file holding the reference records the scene by path in its
182+
`LoadableSceneDependencies`, not in `SerializedFileDependencies`, and nothing appears in its
183+
external-reference table — the serialized `LoadableSceneId` field itself only holds the scene's
184+
GUID. The reference build's `SceneList` asset, a ScriptableObject with a dictionary of
185+
`LoadableSceneId` values, shows this:
186+
187+
```json
188+
{
189+
"Index": 7,
190+
"ID": "70a210050f71a924aa83be7146547111.cfid",
191+
"SourceAssets": [ "Assets/ScriptableObjects/SceneList.asset" ],
192+
"SerializedFileDependencies": [ 8 ],
193+
"LoadableSceneDependencies": [ "Assets/Scenes/Scene2.unity", "Assets/Scenes/Scene1.unity" ],
194+
"ContentHash": "8ad4924ac5e264fde63d8e95a0dab8ab"
195+
}
196+
```
123197

124198
## Build history
125199

@@ -157,26 +231,27 @@ ordered list of the files it depends on:
157231

158232
```json
159233
{
160-
"Index": 3,
234+
"Index": 5,
161235
"ID": "52b43dad178849b42ac753005736e7bb.cfid",
162236
"SourceAssets": [ "Assets/ScriptableObjects/ContentDirectoryRoot.asset" ],
163-
"SerializedFileDependencies": [ 4, 2, 6, 7 ],
164-
"ContentHash": "a77f98db89b6aa1aeaaad01d857e5115"
237+
"SerializedFileDependencies": [ 8, 4, 11, 13, 7 ],
238+
"ContentHash": "c0152db4dd710be51b2decb997325f34"
165239
}
166240
```
167241

168-
The `ContentHash` tells us this asset lives in `a77f98db89b6aa1aeaaad01d857e5115.cf`. Dumping that file
242+
The `ContentHash` tells us this asset lives in `c0152db4dd710be51b2decb997325f34.cf`. Dumping that file
169243
shows the object's references and the file's external-reference table:
170244

171245
```
172-
UnityDataTool dump --stdout a77f98db89b6aa1aeaaad01d857e5115.cf
246+
UnityDataTool dump --stdout c0152db4dd710be51b2decb997325f34.cf
173247
```
174248
```
175249
External References
176250
path(1): "a2a42d71dddef12e8889849faf59bdd7.cfid" GUID: 00000000000000000000000000000000 Type: 0
177251
path(2): "4038ff673d390134d924b57fcbed0432.cfid" GUID: 00000000000000000000000000000000 Type: 0
178252
path(3): "21679be819d6e9146a63bb02a7e51f2f.cfid" GUID: 00000000000000000000000000000000 Type: 0
179253
path(4): "78532141fd7679a458405eb16bdb75fd.cfid" GUID: 00000000000000000000000000000000 Type: 0
254+
path(5): "70a210050f71a924aa83be7146547111.cfid" GUID: 00000000000000000000000000000000 Type: 0
180255
181256
ID: -775554941117088049 (ClassID: 114) MonoBehaviour
182257
...
@@ -196,29 +271,29 @@ through the build. A key goal of the content directory design is to reduce the a
196271

197272
Because of that, the content of the external table is effectively ignored by the loading system for
198273
Content File references. What counts is the ordered dependency list in the manifest. The
199-
`"SerializedFileDependencies": [4, 2, 6, 7]` array corresponds, in exact size and order, to the four
200-
entries of the external table.
274+
`"SerializedFileDependencies": [8, 4, 11, 13, 7]` array corresponds, in exact size and order, to the
275+
five entries of the external table.
201276

202277
So resolving the reference to `SingleAudioClipLoadableReference` above:
203278

204279
1. The `PPtr` has `m_FileID` 3. A non-zero `m_FileID` is a 1-based index into the external table (0
205280
would mean "this same file").
206-
2. Index 3 maps to the 3rd entry of `SerializedFileDependencies`, which is `6`.
207-
3. `ContentLayout.json` entry with `"Index": 6` is `SingleAudioClipLoadableReference.asset`, whose
281+
2. Index 3 maps to the 3rd entry of `SerializedFileDependencies`, which is `11`.
282+
3. `ContentLayout.json` entry with `"Index": 11` is `SingleAudioClipLoadableReference.asset`, whose
208283
`ContentHash` is `5c43454a3823f172a2a326410a36ba6b`.
209284
4. The referenced file is therefore `5c43454a3823f172a2a326410a36ba6b.cf`.
210285

211-
The full mapping for this file, showing how each `m_FileID` in the external table resolves through the
212-
dependency list `[4, 2, 6, 7]` to a content-hash filename:
286+
A partial mapping for this file, showing how `m_FileID` values in the external table resolve through
287+
the dependency list `[8, 4, 11, 13, 7]` to a content-hash filename:
213288

214289
```mermaid
215290
flowchart TD
216-
Root["<b>ContentDirectoryRoot</b><br/>cfid 52b43dad…<br/>file a77f98db….cf<br/>deps [4, 2, 6, 7]"]
217-
Loadable["<b>LoadableAudioClipReference</b><br/>Index 2 · cfid 4038ff67…<br/>file bfcf18a2….cf"]
218-
Single["<b>SingleAudioClipLoadableReference</b><br/>Index 6 · cfid 21679be8…<br/>file 5c43454a….cf"]
291+
Root["<b>ContentDirectoryRoot</b><br/>cfid 52b43dad…<br/>file c0152db4….cf<br/>deps [8, 4, 11, 13, 7]"]
292+
Loadable["<b>LoadableAudioClipReference</b><br/>Index 4 · cfid 4038ff67…<br/>file bfcf18a2….cf"]
293+
Single["<b>SingleAudioClipLoadableReference</b><br/>Index 11 · cfid 21679be8…<br/>file 5c43454a….cf"]
219294
220-
Root -->|"m_FileID 2 → dep 2 → Index 2"| Loadable
221-
Root -->|"m_FileID 3 → dep 6 → Index 6"| Single
295+
Root -->|"m_FileID 2 → dep 4 → Index 4"| Loadable
296+
Root -->|"m_FileID 3 → dep 11 → Index 11"| Single
222297
```
223298

224299
> [!NOTE]

Documentation/playerbuild-format.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ files directly, but they show up throughout UnityDataTool output:
4141
| `resources.assets` | Everything found in `Resources` folders, whether or not a scene references it. Loadable at runtime with `Resources.Load`. |
4242
| `globalgamemanagers` | Core engine data and global project settings (Quality, Graphics, Physics, Tags, Layers, and so on). |
4343
| `globalgamemanagers.assets` | Assets referenced from `globalgamemanagers` (for example a render-pipeline settings ScriptableObject). |
44-
| `Resources/unity_builtin_extra` | Built-in shaders and resources, when referenced by the build. |
44+
| `Resources/unity_builtin_extra` | The shaders in the project's **Always Included Shaders** list, compiled for the target platform. |
4545
| `Resources/unity default resources` | Built-in assets (default materials, fonts, meshes) shipped with the Editor. |
4646

4747
Each SerializedFile can be accompanied by binary companion files:
@@ -199,10 +199,15 @@ differently from the rest of the build output:
199199
errors when analyzing it, even in a build made with TypeTrees enabled (see
200200
[TypeTrees in the Player](#typetrees-in-the-player)).
201201
- **`Resources/unity_builtin_extra`** — built-in shaders (for the Built-in Render Pipeline), stored
202-
in the editor as uncompiled shader source. Only the built-in shaders actually referenced by your content are
203-
compiled and written into the build output. The file is small or absent when you use a scriptable
204-
render pipeline such as URP or HDRP. The project's "Always Included Shaders" list forces specific shaders in even when nothing
205-
references them directly — useful for shaders you locate at runtime with `Shader.Find()`.
202+
in the editor as uncompiled shader source. The player's copy of this file is generated by the
203+
build and holds only the shaders in the project's **Always Included Shaders** list (Graphics
204+
Settings), compiled for the target platform. Built-in shaders that content references without
205+
being in that list are copied into the regular content files like any other asset. The file is
206+
small or absent when you use a scriptable render pipeline such as URP or HDRP. The Always
207+
Included list serves two purposes: it makes those shaders findable at runtime with
208+
`Shader.Find()`, and it is what AssetBundles built with `BuildPipeline.BuildAssetBundles`
209+
rely on when they reference built-in shaders from this file instead of embedding copies (see
210+
[Built-in resources](assetbundle-format.md#built-in-resources) on the AssetBundle page).
206211

207212
## TypeTrees in the Player
208213

29 Bytes
Binary file not shown.

TestCommon/Data/LeadingEdgeBuilds/AssetBundles/AssetBundles.manifest

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
ManifestFileVersion: 0
2-
UnityVersion: 6000.6.0b3
3-
CRC: 3235539447
2+
UnityVersion: 6000.6.0b5
3+
CRC: 3421127840
44
HashAppended: 0
55
AssetBundleManifest:
66
AssetBundleInfos:
@@ -28,3 +28,6 @@ AssetBundleManifest:
2828
Info_5:
2929
Name: a
3030
Dependencies: {}
31+
Info_6:
32+
Name: scenes
33+
Dependencies: {}
240 KB
Binary file not shown.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
ManifestFileVersion: 0
2+
UnityVersion: 6000.6.0b5
3+
CRC: 2898964469
4+
Hashes:
5+
AssetFileHash:
6+
serializedVersion: 2
7+
Hash: d8376e25b646b14d36812f6e9b0b1eaa
8+
TypeTreeHash:
9+
serializedVersion: 2
10+
Hash: ac9f267e89a2ef550e0850cabce2b0d3
11+
IncrementalBuildHash:
12+
serializedVersion: 2
13+
Hash: 219f878f01ce3e202ce41dc4589c7036
14+
HashAppended: 0
15+
ClassTypes:
16+
- Class: 1
17+
Script: {instanceID: 0}
18+
- Class: 4
19+
Script: {instanceID: 0}
20+
- Class: 21
21+
Script: {instanceID: 0}
22+
- Class: 28
23+
Script: {instanceID: 0}
24+
- Class: 48
25+
Script: {instanceID: 0}
26+
- Class: 89
27+
Script: {instanceID: 0}
28+
- Class: 104
29+
Script: {instanceID: 0}
30+
- Class: 157
31+
Script: {instanceID: 0}
32+
- Class: 196
33+
Script: {instanceID: 0}
34+
- Class: 212
35+
Script: {instanceID: 0}
36+
- Class: 213
37+
Script: {instanceID: 0}
38+
SerializeReferenceClassIdentifiers: []
39+
Assets:
40+
- Assets/Scenes/Scene1.unity
41+
- Assets/Scenes/Scene2.unity
42+
Dependencies: []
Binary file not shown.

0 commit comments

Comments
 (0)