diff --git a/Analyzer/Resources/AssetBundle.sql b/Analyzer/Resources/AssetBundle.sql index 85a1987..1040018 100644 --- a/Analyzer/Resources/AssetBundle.sql +++ b/Analyzer/Resources/AssetBundle.sql @@ -8,7 +8,7 @@ -- the AssetBundle object, so this table is empty for Player and ContentDirectory builds. -- For scene bundles the entry names the scene and points at the synthetic Scene object (see -- AssetBundleHandler / SerializedFileSQLiteWriter). -CREATE TABLE IF NOT EXISTS assets( +CREATE TABLE IF NOT EXISTS assetbundle_assets( object INTEGER, name TEXT ); @@ -18,22 +18,22 @@ CREATE TABLE IF NOT EXISTS assets( -- * AssetBundleHandler: an asset's slice of the AssetBundle object's m_PreloadTable. -- * SerializedFileSQLiteWriter: a scene object -> each object in the scene's SerializedFiles. -- * PreloadDataHandler: the PreloadData object's m_Assets. PreloadData is a *separate* Unity --- object (not part of the AssetBundle object) and also exists in Player builds, so this table --- is NOT empty there; but those builds have no scene object, so PreloadDataHandler currently --- attributes the rows to object id -1 (a known limitation). -CREATE TABLE IF NOT EXISTS asset_dependencies( +-- object (not part of the AssetBundle object) and also exists in Player builds (one per scene in its sharedAsset file), +-- so this table is NOT empty there; but those builds have no scene object, so PreloadDataHandler currently +-- attributes the rows to object id -1 (issue 81). +CREATE TABLE IF NOT EXISTS preload_dependencies( object INTEGER, dependency INTEGER ); -CREATE VIEW IF NOT EXISTS asset_view AS +CREATE VIEW IF NOT EXISTS assetbundle_asset_view AS SELECT a.name AS asset_name, o.* -FROM assets a INNER JOIN object_view o ON o.id = a.object; +FROM assetbundle_assets a INNER JOIN object_view o ON o.id = a.object; -CREATE VIEW IF NOT EXISTS asset_dependencies_view AS +CREATE VIEW IF NOT EXISTS preload_dependencies_view AS SELECT a.id, a.asset_name, a.asset_bundle, a.type, od.id dep_id, od.asset_bundle dep_asset_bundle, od.name dep_name, od.type dep_type -FROM asset_view a -INNER JOIN asset_dependencies d ON a.id = d.object +FROM assetbundle_asset_view a +INNER JOIN preload_dependencies d ON a.id = d.object INNER JOIN object_view od ON od.id = d.dependency; diff --git a/Analyzer/Resources/Init.sql b/Analyzer/Resources/Init.sql index b5b936b..4b74cf3 100644 --- a/Analyzer/Resources/Init.sql +++ b/Analyzer/Resources/Init.sql @@ -139,14 +139,14 @@ SELECT m.id material_id, m.name material_name, a.name material_path, m.asset_bun FROM object_view m INNER JOIN refs_view r ON m.id = r.object AND r.property_path = 'm_Shader' INNER JOIN object_view s ON r.referenced_object = s.id -LEFT JOIN assets a ON m.id = a.object; +LEFT JOIN assetbundle_assets a ON m.id = a.object; CREATE VIEW view_material_texture_refs AS SELECT m.id material_id, m.name material_name, a.name material_path, m.asset_bundle material_asset_bundle, t.id texture_id, t.name texture_name, t.asset_bundle texture_asset_bundle FROM object_view m INNER JOIN refs_view r ON r.object = m.id AND property_type = 'Texture' INNER JOIN object_view t ON r.referenced_object = t.id -LEFT JOIN assets a ON m.id = a.object +LEFT JOIN assetbundle_assets a ON m.id = a.object WHERE m.type = 'Material'; -- Special-case type value for the fake Scene object that is sometimes inserted into the object table, @@ -155,8 +155,9 @@ INSERT INTO types (id, name) VALUES (-1, 'Scene'); -- Database schema version. Bump when the schema changes in a way that tools relying on it -- (e.g. find-refs) cannot read from an older database. 1 = normalized refs table (issue #44); --- databases produced before versioning report 0. -PRAGMA user_version = 1; +-- 2 = renamed assets/asset_dependencies tables to assetbundle_assets/preload_dependencies +-- (issue #82); databases produced before versioning report 0. +PRAGMA user_version = 2; PRAGMA synchronous = OFF; PRAGMA journal_mode = MEMORY; diff --git a/Analyzer/SQLite/Commands/SerializedFile/AddAssetDependency.cs b/Analyzer/SQLite/Commands/SerializedFile/AddPreloadDependency.cs similarity index 77% rename from Analyzer/SQLite/Commands/SerializedFile/AddAssetDependency.cs rename to Analyzer/SQLite/Commands/SerializedFile/AddPreloadDependency.cs index 3143abd..9dc9e28 100644 --- a/Analyzer/SQLite/Commands/SerializedFile/AddAssetDependency.cs +++ b/Analyzer/SQLite/Commands/SerializedFile/AddPreloadDependency.cs @@ -5,16 +5,16 @@ namespace UnityDataTools.Analyzer.SQLite.Commands.SerializedFile { /* TABLE DEFINITION: - create table asset_dependencies + create table preload_dependencies ( object INTEGER, dependency INTEGER, PRIMARY KEY (object, dependency) ); */ - internal class AddAssetDependency : AbstractCommand + internal class AddPreloadDependency : AbstractCommand { - protected override string TableName => "asset_dependencies"; + protected override string TableName => "preload_dependencies"; protected override string DDLSource => Resources.AssetBundle; diff --git a/Analyzer/SQLite/Handlers/AssetBundleHandler.cs b/Analyzer/SQLite/Handlers/AssetBundleHandler.cs index f402476..5900e77 100644 --- a/Analyzer/SQLite/Handlers/AssetBundleHandler.cs +++ b/Analyzer/SQLite/Handlers/AssetBundleHandler.cs @@ -7,10 +7,10 @@ namespace UnityDataTools.Analyzer.SQLite.Handlers; // Processes the AssetBundle Unity object, which only exists in content built as AssetBundles. -// It fills the assets table from the object's m_Container (the bundle's explicit assets) and adds -// their dependencies from m_PreloadTable. Player and ContentDirectory builds have no AssetBundle -// object, so this handler never runs for them (asset_dependencies can still get rows from other -// sources there - see AssetBundle.sql). +// It fills the assetbundle_assets table from the object's m_Container (the bundle's explicit +// assets) and adds their dependencies from m_PreloadTable. Player and ContentDirectory builds +// have no AssetBundle object, so this handler never runs for them (preload_dependencies can still +// get rows from other sources there - see AssetBundle.sql). public class AssetBundleHandler : ISQLiteHandler { SqliteCommand m_InsertCommand; @@ -20,8 +20,8 @@ public class AssetBundleHandler : ISQLiteHandler // This name must match the one SerializedFileSQLiteWriter derives from the scene's file name // so both compute the same synthetic Scene object id. They only agree for // BuildPipeline.BuildAssetBundles; for Scriptable Build Pipeline / Addressables and other - // pipelines the writer never creates the Scene object, so the assets row written below points - // at an object id that has no objects-table row (a dangling reference). + // pipelines the writer never creates the Scene object, so the assetbundle_assets row written + // below points at an object id that has no objects-table row (a dangling reference). private Regex m_SceneNameRegex = new Regex(@"([^//]+)\.unity"); public void Init(SqliteConnection db) @@ -32,13 +32,13 @@ public void Init(SqliteConnection db) m_InsertCommand = db.CreateCommand(); - m_InsertCommand.CommandText = "INSERT INTO assets(object, name) VALUES(@object, @name)"; + m_InsertCommand.CommandText = "INSERT INTO assetbundle_assets(object, name) VALUES(@object, @name)"; m_InsertCommand.Parameters.Add("@object", SqliteType.Integer); m_InsertCommand.Parameters.Add("@name", SqliteType.Text); m_InsertDepCommand = db.CreateCommand(); - m_InsertDepCommand.CommandText = "INSERT INTO asset_dependencies(object, dependency) VALUES(@object, @dependency)"; + m_InsertDepCommand.CommandText = "INSERT INTO preload_dependencies(object, dependency) VALUES(@object, @dependency)"; m_InsertDepCommand.Parameters.Add("@object", SqliteType.Integer); m_InsertDepCommand.Parameters.Add("@dependency", SqliteType.Integer); } @@ -93,10 +93,10 @@ public void Finalize(SqliteConnection db) { using var command = new SqliteCommand(); command.Connection = db; - command.CommandText = "CREATE INDEX asset_dependencies_object ON asset_dependencies(object)"; + command.CommandText = "CREATE INDEX preload_dependencies_object ON preload_dependencies(object)"; command.ExecuteNonQuery(); - command.CommandText = "CREATE INDEX asset_dependencies_dependency ON asset_dependencies(dependency)"; + command.CommandText = "CREATE INDEX preload_dependencies_dependency ON preload_dependencies(dependency)"; command.ExecuteNonQuery(); } diff --git a/Analyzer/SQLite/Handlers/PreloadDataHandler.cs b/Analyzer/SQLite/Handlers/PreloadDataHandler.cs index e448484..7d57a90 100644 --- a/Analyzer/SQLite/Handlers/PreloadDataHandler.cs +++ b/Analyzer/SQLite/Handlers/PreloadDataHandler.cs @@ -7,8 +7,8 @@ namespace UnityDataTools.Analyzer.SQLite.Handlers; // Processes the PreloadData object found in scene bundles. Its m_Assets list is recorded as the -// scene's dependencies (asset_dependencies), so it is meaningful only alongside a synthetic Scene -// object. This is AssetBundle-specific in practice: Player builds also contain a PreloadData +// scene's dependencies (preload_dependencies), so it is meaningful only alongside a synthetic +// Scene object. This is AssetBundle-specific in practice: Player builds also contain a PreloadData // object but have no scene object, so ctx.SceneId is -1 there and the rows below are written // against object id -1 (a limitation, not intended output). ContentDirectory builds have neither. public class PreloadDataHandler : ISQLiteHandler @@ -19,7 +19,7 @@ public void Init(SqliteConnection db) { m_InsertDepCommand = db.CreateCommand(); m_InsertDepCommand.Connection = db; - m_InsertDepCommand.CommandText = "INSERT INTO asset_dependencies(object, dependency) VALUES(@object, @dependency)"; + m_InsertDepCommand.CommandText = "INSERT INTO preload_dependencies(object, dependency) VALUES(@object, @dependency)"; m_InsertDepCommand.Parameters.Add("@object", SqliteType.Integer); m_InsertDepCommand.Parameters.Add("@dependency", SqliteType.Integer); } diff --git a/Analyzer/SQLite/Writers/SerializedFileSQLiteWriter.cs b/Analyzer/SQLite/Writers/SerializedFileSQLiteWriter.cs index 2d563f2..86cbe13 100644 --- a/Analyzer/SQLite/Writers/SerializedFileSQLiteWriter.cs +++ b/Analyzer/SQLite/Writers/SerializedFileSQLiteWriter.cs @@ -43,8 +43,8 @@ public class SerializedFileSQLiteWriter : IDisposable // Build Pipeline / Addressables ("CAB-") or the Multi-Process Build // Pipeline ("CAB-"), nor player-build scenes ("level0", "level1", ...). For // those builds no synthetic Scene object is created (see the scene handling in - // WriteSerializedFile), so the scene rows AssetBundleHandler writes into assets end up - // dangling and PreloadDataHandler attributes preload dependencies to SceneId -1. + // WriteSerializedFile), so the scene rows AssetBundleHandler writes into assetbundle_assets + // end up dangling and PreloadDataHandler attributes preload dependencies to SceneId -1. private Regex m_RegexSceneFile = new(@"BuildPlayer-([^\.]+)(?:\.sharedAssets)?"); // Rebuilt for each serialized file: maps a PPtr's local m_FileID (0 = this file, 1..N = an @@ -75,7 +75,7 @@ public class SerializedFileSQLiteWriter : IDisposable private AddSerializedFile m_AddSerializedFileCommand = new AddSerializedFile(); private AddObject m_AddObjectCommand = new AddObject(); private AddType m_AddTypeCommand = new AddType(); - private AddAssetDependency m_InsertDepCommand = new AddAssetDependency(); + private AddPreloadDependency m_InsertDepCommand = new AddPreloadDependency(); private bool m_Initialized; private SqliteConnection m_Database; @@ -166,7 +166,7 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con // A scene has no single Unity object to represent it, yet a scene bundle lists the scene // (by its .unity path) as the bundle's asset and other objects/preloads need something to // hang off of. So for scene bundles we synthesize one "Scene" object per scene and use it - // as the target of the assets row (AssetBundleHandler) and of the scene's content and + // as the target of the assetbundle_assets row (AssetBundleHandler) and of the scene's content and // preload dependencies (below and PreloadDataHandler). This only happens when the file // name matches m_RegexSceneFile; see its LIMITATION note for the builds this misses (issue 81). var match = m_RegexSceneFile.Match(relativePath); diff --git a/Documentation/analyze-examples.md b/Documentation/analyze-examples.md index 66787a6..67a5523 100644 --- a/Documentation/analyze-examples.md +++ b/Documentation/analyze-examples.md @@ -245,9 +245,9 @@ This is a large subject, see [Comparing Builds](comparing-builds.md). UnityDataTool works on the output of a Unity build, which, by its very nature, only contains the crucial data needed to efficiently load built content in the Player. It does not include complete information about the assets and scenes in the project that was used to create that build. You may want to match content back to the original source asset or scene. For example if the size of an AssetBundle has unexpectedly changed between builds then you may want to track down which source assets could be responsible for that change. Or you may want to confirm that some particular image has been included in the build. -For AssetBundles partial asset information can be found in the m_Containers list, inside the AssetBundle object. This records assets that were explicitly added to AssetBundles. In the database this can be found in the `assets` table. However, assets that are included in the build implicitly (because they are referenced from the explicitly added assets) will not be recorded anywhere in the AssetBundle content. +For AssetBundles partial asset information can be found in the m_Containers list, inside the AssetBundle object. This records assets that were explicitly added to AssetBundles. In the database this can be found in the `assetbundle_assets` table. However, assets that are included in the build implicitly (because they are referenced from the explicitly added assets) will not be recorded anywhere in the AssetBundle content. -Similarly for a player build the only paths populated in the `assets` table are the scenes from the Build Profile Scene List. The paths of the assets in the sharedAsset files is not recorded anywhere in the build output. +For a player build the `assetbundle_assets` table is empty (player builds don’t contain an AssetBundle object), and the paths of assets in the sharedassets files are not recorded anywhere in the build output. In many cases the source asset can be inferred based on your specific knowledge of your project, and how the build was configured. For example the level files in a Player build match the Scenes in the Build Profile Scene list. And the content of AssetBundles is driven from the assignment of specific assets to those AssetBundles (or Addressable groups), along with assets they depend on. diff --git a/Documentation/analyzer.md b/Documentation/analyzer.md index 62297b6..2ecf285 100644 --- a/Documentation/analyzer.md +++ b/Documentation/analyzer.md @@ -50,14 +50,14 @@ duplicated assets. It also lists all the AssetBundles where the asset was found. If the `--skip-crc` option is used, there will be a lot of false positives in that view. Otherwise, it should be very accurate because CRCs are used to determine if objects are identical. -## asset_view (AssetBundleProcessor) +## assetbundle_asset_view (AssetBundleProcessor) This view lists all the assets that have been explicitly assigned to AssetBundles. The dependencies that were automatically added by Unity at build time won't appear in this view. The columns are the same as those in the *object_view* with the addition of the *asset_name* that contains the filename of the asset. -## asset_dependencies_view (AssetBundleProcessor) +## preload_dependencies_view (AssetBundleProcessor) This view lists the dependencies of all the assets. You can filter by id or asset_name to get all the dependencies of an asset. Conversely, filtering by dep_id will return all the assets that diff --git a/ReferenceFinder/ReferenceFinderTool.cs b/ReferenceFinder/ReferenceFinderTool.cs index e5e65ea..80fa580 100644 --- a/ReferenceFinder/ReferenceFinderTool.cs +++ b/ReferenceFinder/ReferenceFinderTool.cs @@ -19,9 +19,10 @@ public ReferenceTreeNode(long id) public class ReferenceFinderTool { - // Minimum analyze database schema version find-refs can read. The normalized refs table - // (issue #44) is version 1; databases produced before schema versioning report 0. - const long RequiredSchemaVersion = 1; + // Minimum analyze database schema version find-refs can read. Version 2 renamed the + // assets/asset_view tables this tool queries to assetbundle_assets/assetbundle_asset_view + // (issue #82), so an older database (version 1 or the pre-versioning 0) cannot be read. + const long RequiredSchemaVersion = 2; SqliteCommand m_GetRefsCommand; SqliteCommand m_GetObjectCommand; @@ -137,7 +138,7 @@ int FindReferences(SqliteConnection db, string outputFile, IList objectIds m_Writer = toStdout ? Console.Out : new StreamWriter(outputFile); m_GetRefsCommand = db.CreateCommand(); - m_GetRefsCommand.CommandText = @"SELECT object, property_path, EXISTS (SELECT * FROM assets a WHERE a.object = r.object) FROM refs_view r WHERE referenced_object = @id"; + m_GetRefsCommand.CommandText = @"SELECT object, property_path, EXISTS (SELECT * FROM assetbundle_assets a WHERE a.object = r.object) FROM refs_view r WHERE referenced_object = @id"; m_GetRefsCommand.Parameters.Add("@id", SqliteType.Integer); // Resolve the 'm_Script' property path to its id once so the per-object script lookup below @@ -190,7 +191,7 @@ FROM object_view o ProcessReferences(objectIds[i], findAll); - command.CommandText = "SELECT asset_name, asset_bundle, serialized_file FROM asset_view WHERE id = @id"; + command.CommandText = "SELECT asset_name, asset_bundle, serialized_file FROM assetbundle_asset_view WHERE id = @id"; foreach (var root in m_Roots) { diff --git a/UnityDataTool.Tests/ExpectedDataGenerator.cs b/UnityDataTool.Tests/ExpectedDataGenerator.cs index 4963acf..9582eb5 100644 --- a/UnityDataTool.Tests/ExpectedDataGenerator.cs +++ b/UnityDataTool.Tests/ExpectedDataGenerator.cs @@ -38,7 +38,7 @@ public static void Generate(Context context) @"SELECT (SELECT COUNT(*) FROM animation_clips), (SELECT COUNT(*) FROM asset_bundles), - (SELECT COUNT(*) FROM assets), + (SELECT COUNT(*) FROM assetbundle_assets), (SELECT COUNT(*) FROM audio_clips), (SELECT COUNT(*) FROM meshes), (SELECT COUNT(*) FROM monoscripts), diff --git a/UnityDataTool.Tests/UnityDataToolAssetBundleTests.cs b/UnityDataTool.Tests/UnityDataToolAssetBundleTests.cs index acffc04..f814a95 100644 --- a/UnityDataTool.Tests/UnityDataToolAssetBundleTests.cs +++ b/UnityDataTool.Tests/UnityDataToolAssetBundleTests.cs @@ -329,7 +329,7 @@ private void ValidateDatabase(string databasePath, bool withRefs) @"SELECT (SELECT COUNT(*) FROM animation_clips), (SELECT COUNT(*) FROM asset_bundles), - (SELECT COUNT(*) FROM assets), + (SELECT COUNT(*) FROM assetbundle_assets), (SELECT COUNT(*) FROM audio_clips), (SELECT COUNT(*) FROM meshes), (SELECT COUNT(*) FROM objects), diff --git a/UnityDataTool.Tests/UnityDataToolPlayerDataTests.cs b/UnityDataTool.Tests/UnityDataToolPlayerDataTests.cs index a010df2..3e84682 100644 --- a/UnityDataTool.Tests/UnityDataToolPlayerDataTests.cs +++ b/UnityDataTool.Tests/UnityDataToolPlayerDataTests.cs @@ -51,7 +51,7 @@ public async Task Analyze_PlayerData_DatabaseCorrect() cmd.CommandText = @"SELECT (SELECT COUNT(*) FROM asset_bundles), - (SELECT COUNT(*) FROM assets), + (SELECT COUNT(*) FROM assetbundle_assets), (SELECT COUNT(*) FROM objects), (SELECT COUNT(*) FROM refs), (SELECT COUNT(*) FROM serialized_files)";