Skip to content

[#131] Support ContentLayout v3 (Unity 6.7) with v2 backward compatibility - #147

Open
SkowronskiAndrew wants to merge 3 commits into
unity6.7supportfrom
issue131-contentlayout-v3
Open

SkowronskiAndrew wants to merge 3 commits into
unity6.7supportfrom
issue131-contentlayout-v3

Conversation

@SkowronskiAndrew

Copy link
Copy Markdown
Collaborator

Summary

Fixes #131.

Unity 6.7 changes the ContentLayout.json schema from version 2 to version 3: ID becomes StableId (the bare identity hash, no .cfid extension), ContentHash is replaced by ArtifactIndex, LoadableDependencies and RootAssets reference loadables by index instead of ObjectIdHash (which was deleted), and the loadable entries lose AssetPath and OutputLFID — 6.7 no longer remaps objects into clusters, so LFID now records the output-file id directly.

This PR makes analyze accept both versions with a single database schema, so the same queries work on output from Unity 6.6 and 6.7. A v2 file is upgraded in memory to the v3 model on import; the C# model UnityDataTools.Models.ContentLayout now tracks v3, and the v2 schema stays available as a reference definition in UnityDataTools.Models.V2.

Changes

Models (UnityDataModels)

  • ContentLayout.cs updated to the v3 schema (CurrentVersion = 3).
  • The v2 classes preserved in ContentLayoutV2.cs under the UnityDataTools.Models.V2 namespace.

Analyzer

  • ContentLayoutParser peeks at Version (streaming read) and deserializes with the matching model; unsupported versions get a clear error naming versions 2 and 3.
  • New internal ContentLayoutV2Upgrader converts a v2 layout to the v3 model: strips .cfid from the stable ids and resolves the hash-based references (ObjectIdHash, ContentHash) to indices. The v2-only per-loadable source data travels in a small side record.
  • The content_layout* tables move to the v3 shape (user_version 7 → 8):
    • content_layout_serialized_files: cfidstable_id, content_hashartifact_index (hash and filename are derived in the views via the artifact link).
    • content_layout_loadable_objects: keyed by loadable_index (json array index); lfid takes the v3 meaning (output-file id); is_root_asset stores the 1-based root input position (0 = not a root); the v2-only columns asset_path and source_lfid exist only in databases imported from a v2 layout (the importer picks the DDL variant, so v3 databases carry no always-NULL legacy columns).
    • content_layout_loadable_dependencies references loadable_index.
  • find-refs identifies loadable chain roots by GUID instead of the removed asset path.

Test data and tests

  • The previous v2 layout of the LeadingEdge build is archived at TestCommon/Data/ContentLayoutVersions/v2 as a permanent backward-compat fixture, with new tests (AnalyzeContentLayoutV2Tests) covering the upgrade path.
  • The LeadingEdge ContentDirectory reference data is regenerated with a Unity 6.7 editor (v3 layout, SerializedFile v26 content); existing tests updated to the new schema and data.
  • Note: the committed UnityFileSystemApi native libraries are still 6.6-era. Reading the regenerated 6.7 data requires a 6.7 build of the library, so many CI tests are expected to fail until 6.7 builds of the dll/dylib/so land on this branch (tracked separately). The test results below are from a local run with a locally built 6.7 dll.

Documentation

  • contentlayout.md: v3 member table, stable-id explanation, and a versioning section documenting the v2→v3 differences.
  • contentlayout-database.md: updated column reference plus a "Layout version differences" section.
  • contentdirectory-format.md: worked examples refreshed from the regenerated 6.7 build.
  • analyzer-schema.md: user_version 8 row.

Testing

  • dotnet test — full suite green on Windows (839 passed / 10 skipped): v2 fixture import, v3 layout-only and layout+content analyze, reference resolution, find-refs across content files, build-history matching.
  • Ad-hoc: analyzed a real-world 9 MB v2 layout (13k files, 8.9k loadables) — imports in ~0.9 s with all hash→index resolutions succeeding.

🤖 Generated with Claude Code

…ility

The Unity 6.7 ContentLayout.json schema (v3) renames ID to StableId (no
.cfid extension), replaces ContentHash with ArtifactIndex, references
loadables by index instead of ObjectIdHash, and drops the loadable
AssetPath/OutputLFID fields (no more remapping into clusters).

UnityDataTools.Models.ContentLayout now tracks v3; the v2 schema is
preserved as a reference definition in UnityDataTools.Models.V2. Analyze
accepts both versions: v2 files are upgraded in memory to the v3 model
(ContentLayoutV2Upgrader), so a single write path and a single database
schema serve both. The content_layout tables move to the v3 shape
(loadable_index key, stable_id, artifact_index, is_root_asset holding
the 1-based root position); the v2-only source data (asset_path,
source_lfid) lands in extra columns that exist only in databases
imported from a v2 layout. PRAGMA user_version bumped to 8.

The previous v2 layout of the LeadingEdge build is archived at
TestCommon/Data/ContentLayoutVersions/v2 as a permanent fixture, the
LeadingEdge ContentDirectory reference data is regenerated with a 6.7
editor (v3 layout), and UnityFileSystemApi.dll is updated to a local
6.7 build (debug config, Windows only - the mac/linux libraries still
need a 6.7 build).
Windows, Mac, Linux builds from release candidate build

```sql
SELECT * FROM content_layout_loadable_objects_view ORDER BY is_root_asset DESC, asset_path;
SELECT * FROM content_layout_loadable_objects_view ORDER BY is_root_asset DESC, name;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the asset_path really reduces the usefulness of the content_layout_loadable_objects_view, because the asset_path really makes the loadable understandable.

For v2-based imports we can use the asset_path directly from the Loadable structure.

For v3 we need content_layout_loadable_objects_view to incorporate the asset_path from content_layout_source_assets based on the matching serialized file index. We only expect a single match per serialized_file_index (multiple entries are only expected for special cases, like MonoScript or built-in resources)

So it seems we probably need a version specific definition of the view.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread UnityDataModels/ContentLayout.cs Outdated
/// the PersistentManager at runtime and have no artifact. Only written when true; absent means false.</summary>
public bool IsBuiltIn;

/// <summary>The source assets included in this SerializedFile.</summary>

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Part of the trickiness of handling the removal of source_asset is that this remains an array. So a LoadableObjectId, which truly can only come from a single single source asset, now has a pointer to the serialized file that contains it, which has room for 0-n source assets.

For regular cases there will be 1 and only 1 entry here. We cannot make it an single field (yet?) because there is a special case for MonoScripts (clustered) and perhaps the built in files.

The comment can be extended a bit to mention this is normally only single entry.

For the moment it is best if our queries that deal with LoadableObjectId join in the SourceAssets.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets correct this at the same time, because it is relevant to my comments about v2/v3 differences for source_asset.

For v2 the above is true. For v3 we handle do NOT cluster assets together even if there is a circular reference. Circular references should still be avoided but they do not impact the layout, they only cause inefficiencies at loading time.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@SkowronskiAndrew SkowronskiAndrew left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments related to loadable -> source_assets mapping that we should address.

…ions

The loadables view is version-specific again: v2 selects the recorded
asset_path directly, v3 derives it from the containing file's source
assets (normally a single entry per file). find-refs reports the asset
path for loadable chain roots as before. Also documents that
SourceAssets normally holds one entry, and corrects the circular-
reference note for 6.7 (no more clustering; loading-time cost only).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant