1- using Newtonsoft . Json ;
1+ using Analyzer . SQLite . Parsers ;
2+ using Analyzer . SQLite . Writers ;
3+ using Newtonsoft . Json ;
24using Newtonsoft . Json . Linq ;
35using System ;
46using System . Collections . Generic ;
57using System . Diagnostics ;
68using System . IO ;
79using UnityDataTools . Analyzer . Build ;
8- using UnityDataTools . Analyzer . SQLite ;
10+ using UnityDataTools . Analyzer . SQLite . Handlers ;
911using UnityDataTools . FileSystem ;
1012
1113namespace UnityDataTools . Analyzer ;
@@ -14,6 +16,12 @@ public class AnalyzerTool
1416{
1517 bool m_Verbose = false ;
1618
19+ public List < ISQLiteFileParser > parsers = new List < ISQLiteFileParser > ( )
20+ {
21+ new AddressablesBuildLayoutParser ( ) ,
22+ new SerializedFileParser ( ) ,
23+ } ;
24+
1725 public int Analyze (
1826 string path ,
1927 string databaseName ,
@@ -24,11 +32,19 @@ public int Analyze(
2432 {
2533 m_Verbose = verbose ;
2634
27- using SQLiteWriter writer = new ( databaseName , skipReferences ) ;
35+ // TODO: skipReferences needs to be passed into AssetBundleWriter
36+ using SQLiteWriter writer = new ( databaseName ) ;
2837
2938 try
3039 {
3140 writer . Begin ( ) ;
41+ foreach ( var parser in parsers )
42+ {
43+ parser . Verbose = verbose ;
44+ parser . SkipReferences = skipReferences ;
45+ parser . Init ( writer . Connection ) ;
46+
47+ }
3248 }
3349 catch ( Exception e )
3450 {
@@ -47,13 +63,31 @@ public int Analyze(
4763 int i = 1 ;
4864 foreach ( var file in files )
4965 {
50- if ( Path . GetExtension ( file ) == ".json" && IsAddressablesBuildReport ( file ) )
66+ bool foundParser = false ;
67+ foreach ( var parser in parsers )
5168 {
52- ProcessAddressablesBuild ( file , writer , i , files . Length ) ;
53- ++ i ;
54- continue ;
69+ if ( parser . CanParse ( file ) )
70+ {
71+ foundParser = true ;
72+ Console . Error . WriteLine ( file ) ;
73+ try
74+ {
75+ parser . Parse ( file ) ;
76+ ReportProgress ( Path . GetRelativePath ( path , file ) , i , files . Length ) ;
77+ }
78+ catch ( Exception e )
79+ {
80+ EraseProgressLine ( ) ;
81+ Console . Error . WriteLine ( ) ;
82+ Console . Error . WriteLine ( $ "Error processing file: { file } ") ;
83+ Console . WriteLine ( $ "{ e . GetType ( ) } : { e . Message } ") ;
84+ if ( m_Verbose )
85+ Console . WriteLine ( e . StackTrace ) ;
86+ }
87+ ++ i ;
88+ }
5589 }
56- if ( ShouldIgnoreFile ( file ) )
90+ if ( ! foundParser )
5791 {
5892 var relativePath = Path . GetRelativePath ( path , file ) ;
5993
@@ -63,152 +97,25 @@ public int Analyze(
6397 Console . WriteLine ( $ "Ignoring { relativePath } ") ;
6498 }
6599 ++ i ;
66- continue ;
67100 }
68-
69- ProcessFile ( file , path , writer , i , files . Length ) ;
70- ++ i ;
71101 }
72102
73103 Console . WriteLine ( ) ;
74104 Console . WriteLine ( "Finalizing database..." ) ;
75105
76106 writer . End ( ) ;
107+ foreach ( var parser in parsers )
108+ {
109+ parser . Dispose ( ) ;
110+ }
77111
78- timer . Stop ( ) ;
112+ timer . Stop ( ) ;
79113 Console . WriteLine ( ) ;
80114 Console . WriteLine ( $ "Total time: { ( timer . Elapsed . TotalMilliseconds / 1000.0 ) : F3} s") ;
81115
82116 return 0 ;
83117 }
84118
85- bool ShouldIgnoreFile ( string file )
86- {
87- // Unfortunately there is no standard extension for AssetBundles, and SerializedFiles often have no extension at all.
88- // Also there is also no distinctive signature at the start of a SerializedFile to immediately recognize it based on its first bytes.
89- // This makes it difficult to use the "--search-pattern" argument to only pick those files.
90-
91- // Hence to reduce noise in UnityDataTool output we filter out files that we have a high confidence are
92- // NOT SerializedFiles or Unity Archives.
93-
94- string fileName = Path . GetFileName ( file ) ;
95- string extension = Path . GetExtension ( file ) ;
96-
97- return IgnoredFileNames . Contains ( fileName ) || IgnoredExtensions . Contains ( extension ) ;
98- }
99-
100- // These lists are based on expected output files in Player, AssetBundle, Addressables and ECS builds.
101- // However this is by no means exhaustive.
102- private static readonly HashSet < string > IgnoredFileNames = new ( )
103- {
104- ".DS_Store" , "boot.config" , "archive_dependencies.bin" , "scene_info.bin" , "app.info" , "link.xml" ,
105- "catalog.bin" , "catalog.hash"
106- } ;
107-
108- private static readonly HashSet < string > IgnoredExtensions = new ( )
109- {
110- ".txt" , ".resS" , ".resource" , ".json" , ".dll" , ".pdb" , ".exe" , ".manifest" , ".entities" , ".entityheader"
111- } ;
112-
113- void ProcessFile ( string file , string rootDirectory , SQLiteWriter writer , int fileIndex , int cntFiles )
114- {
115- try
116- {
117- UnityArchive archive = null ;
118-
119- try
120- {
121- archive = UnityFileSystem . MountArchive ( file , "archive:" + Path . DirectorySeparatorChar ) ;
122- }
123- catch ( NotSupportedException )
124- {
125- // It wasn't an AssetBundle, try to open the file as a SerializedFile.
126-
127- var relativePath = Path . GetRelativePath ( rootDirectory , file ) ;
128- writer . WriteSerializedFile ( relativePath , file , Path . GetDirectoryName ( file ) ) ;
129-
130- ReportProgress ( relativePath , fileIndex , cntFiles ) ;
131- }
132-
133- if ( archive != null )
134- {
135- try
136- {
137- var assetBundleName = Path . GetRelativePath ( rootDirectory , file ) ;
138-
139- writer . BeginAssetBundle ( assetBundleName , new FileInfo ( file ) . Length ) ;
140- ReportProgress ( assetBundleName , fileIndex , cntFiles ) ;
141-
142- foreach ( var node in archive . Nodes )
143- {
144- if ( node . Flags . HasFlag ( ArchiveNodeFlags . SerializedFile ) )
145- {
146- try
147- {
148- writer . WriteSerializedFile ( node . Path , "archive:/" + node . Path , Path . GetDirectoryName ( file ) ) ;
149- }
150- catch ( Exception e )
151- {
152- EraseProgressLine ( ) ;
153- Console . Error . WriteLine ( $ "Error processing { node . Path } in archive { file } ") ;
154- Console . Error . WriteLine ( e ) ;
155- Console . WriteLine ( ) ;
156- }
157- }
158- }
159- }
160- finally
161- {
162- writer . EndAssetBundle ( ) ;
163- archive . Dispose ( ) ;
164- }
165- }
166- EraseProgressLine ( ) ;
167- }
168- catch ( NotSupportedException )
169- {
170- EraseProgressLine ( ) ;
171- Console . Error . WriteLine ( ) ;
172- //A "failed to load" error will already be logged by the UnityFileSystem library
173- }
174- catch ( Exception e )
175- {
176- EraseProgressLine ( ) ;
177- Console . Error . WriteLine ( ) ;
178- Console . Error . WriteLine ( $ "Error processing file: { file } ") ;
179- Console . WriteLine ( $ "{ e . GetType ( ) } : { e . Message } ") ;
180- if ( m_Verbose )
181- Console . WriteLine ( e . StackTrace ) ;
182- }
183- }
184-
185-
186-
187- void ProcessAddressablesBuild ( string file , SQLiteWriter writer , int fileIndex , int cntFiles )
188- {
189- try
190- {
191- Console . Error . WriteLine ( file ) ;
192- using ( StreamReader reader = File . OpenText ( file ) )
193- {
194- JsonSerializer serializer = new JsonSerializer ( ) ;
195- BuildLayout buildLayout = ( BuildLayout ) serializer . Deserialize ( reader , typeof ( BuildLayout ) ) ;
196- writer . WriteAddressablesBuild ( file , buildLayout ) ;
197- ReportProgress ( file , fileIndex , cntFiles ) ;
198- }
199- }
200- catch ( Exception e )
201- {
202- EraseProgressLine ( ) ;
203- Console . Error . WriteLine ( ) ;
204- Console . Error . WriteLine ( $ "Error processing file: { file } ") ;
205- Console . WriteLine ( $ "{ e . GetType ( ) } : { e . Message } ") ;
206- if ( m_Verbose )
207- Console . WriteLine ( e . StackTrace ) ;
208- }
209-
210- }
211-
212119 int m_LastProgressMessageLength = 0 ;
213120
214121 void ReportProgress ( string relativePath , int fileIndex , int cntFiles )
@@ -235,45 +142,4 @@ void EraseProgressLine()
235142 else
236143 Console . WriteLine ( ) ;
237144 }
238-
239- bool IsAddressablesBuildReport ( string filename )
240- {
241- // Read the first line of the JSON file and check if it contains BuildResultHash
242- string firstLine = "" ;
243- try
244- {
245- using ( StreamReader reader = new StreamReader ( filename ) )
246- {
247- firstLine = reader . ReadLine ( ) ;
248- if ( firstLine != null )
249- {
250- // Remove trailing comma if present and add closing brace to make it valid JSON
251- if ( firstLine . TrimEnd ( ) . EndsWith ( "," ) )
252- {
253- firstLine = firstLine . TrimEnd ( ) . TrimEnd ( ',' ) + "}" ;
254- }
255-
256- using ( JsonTextReader jsonReader = new JsonTextReader ( new StringReader ( firstLine ) ) )
257- {
258- JsonSerializer serializer = new JsonSerializer ( ) ;
259- var jsonObject = serializer . Deserialize < JObject > ( jsonReader ) ;
260-
261- // If the file has BuildResultHash, process it as an Addressables build
262- if ( jsonObject != null && jsonObject [ "BuildResultHash" ] != null )
263- {
264- return true ;
265- }
266- }
267- }
268- }
269- }
270- catch ( Exception e )
271- {
272- if ( m_Verbose )
273- {
274- Console . Error . WriteLine ( $ "Error reading JSON file { filename } : { e . Message } ") ;
275- }
276- }
277- return false ;
278- }
279145}
0 commit comments