From 2d116a896e4238eac9b1c5e01ec88fdb08af2d74 Mon Sep 17 00:00:00 2001 From: Andrew Skowronski Date: Fri, 26 Sep 2025 16:20:18 -0400 Subject: [PATCH] WIP Attempt to support analysis of more than one build If two versions of the same builds are in separate directories then we can potentially support analysis into a single DB by incorporating the path into the unique id generation. However so far this approach is breaking the asset dependency view, so either this approach is fundamentally flawed or a few more fixes could complete it. Even with this fix dependencies between AssetBundles are fundamentally not "1-1" if different AssetBundles have the same filenames and are in the same folder - we don't know which one to pick. This can be the case with AssetBundle variants or other cases where the game logic konws which AssetBundle to load at runtime and only one of the "conflicting" bundles will be loaded. How analyze should properly handle this case is TBD. --- Analyzer/SQLite/SQLiteWriter.cs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/Analyzer/SQLite/SQLiteWriter.cs b/Analyzer/SQLite/SQLiteWriter.cs index a463f3e..aee82f6 100644 --- a/Analyzer/SQLite/SQLiteWriter.cs +++ b/Analyzer/SQLite/SQLiteWriter.cs @@ -177,7 +177,14 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con using var sf = UnityFileSystem.OpenSerializedFile(fullPath); using var reader = new UnityFileReader(fullPath, 64 * 1024 * 1024); using var pptrReader = new PPtrAndCrcProcessor(sf, reader, containingFolder, AddReference); - int serializedFileId = m_SerializedFileIdProvider.GetId(Path.GetFileName(fullPath).ToLower()); + + // Determine a unique id for this serialized file. + // When processing AssetBundles the fullPath is a virtual path inside the AssetBundle. + // Normally the serialized files have unique names across the output of an AssetBundle build. + // But we mix in the containing folder in case analyze is being run on the output of more than one build. + var uniquePath = $"{Path.GetFileName(fullPath).ToLower()}-{containingFolder}"; + int serializedFileId = m_SerializedFileIdProvider.GetId(uniquePath); + int sceneId = -1; using var transaction = m_Database.BeginTransaction(); @@ -192,7 +199,8 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con // There is no Scene object in Unity (a Scene is the full content of a // SerializedFile). We generate an object id using the name of the Scene // as SerializedFile name, and the object id 0. - sceneId = m_ObjectIdProvider.GetId((m_SerializedFileIdProvider.GetId(sceneName), 0)); + string uniqueSceneName = $"{sceneName}-{containingFolder}"; + sceneId = m_ObjectIdProvider.GetId((m_SerializedFileIdProvider.GetId(uniqueSceneName), 0)); // There are 2 SerializedFiles per Scene, one ends with .sharedAssets. This is a // dirty trick to avoid inserting the scene object a second time. @@ -239,8 +247,14 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con m_LocalToDbFileId.Add(localId++, serializedFileId); foreach (var extRef in sf.ExternalReferences) { - m_LocalToDbFileId.Add(localId++, - m_SerializedFileIdProvider.GetId(extRef.Path.Substring(extRef.Path.LastIndexOf('/') + 1).ToLower())); + // References inside an AssetBundle point to the SerializedFile, not the AssetBundle. + // This works provided the AssetBundle is loaded, making the Serialized Files visible, and those + // files are normally unique per build output. + // To support analyzing multiple builds in different folders we mix in the containing folder to + // generate the unique id. If multiple AssetBundles in the same folder have the same serialized file name + // then the reference is ambiguous and there will be an SQL unique constraint exception. + string uniqueExternalPath = $"{extRef.Path.Substring(extRef.Path.LastIndexOf('/') + 1).ToLower()}-{containingFolder}"; + m_LocalToDbFileId.Add(localId++, m_SerializedFileIdProvider.GetId(uniqueExternalPath)); } foreach (var obj in sf.Objects)