-
Notifications
You must be signed in to change notification settings - Fork 61
Add Addressables Report support #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
timt-unity3d
wants to merge
13
commits into
main
Choose a base branch
from
add-buildlayout-support
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 12 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
8d345e2
add in explict assets from build layout files
timt-unity3d bb1168f
added addressables build reports
timt-unity3d e308210
initial import of several additional commands
timt-unity3d 6196d23
add all addressable tables
timt-unity3d 3134ff5
move to serialized file commands
timt-unity3d 015472e
move DDL into individual abstract commands
timt-unity3d 6206b19
refactor sql files to individual files
timt-unity3d 8925e43
Add separate parsers
timt-unity3d 0534f4d
fix initialization
timt-unity3d 2ae27eb
added more thorough documentation
timt-unity3d f369382
Merge branch 'main' into add-buildlayout-support
timt-unity3d 8303ae0
typo fixes from code reviews
timt-unity3d 8a58036
add missing build file
timt-unity3d File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,13 @@ | ||
using System; | ||
using Analyzer.SQLite.Parsers; | ||
using Analyzer.SQLite.Writers; | ||
using Newtonsoft.Json; | ||
using Newtonsoft.Json.Linq; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.IO; | ||
using UnityDataTools.Analyzer.SQLite; | ||
using UnityDataTools.Analyzer.Build; | ||
using UnityDataTools.Analyzer.SQLite.Handlers; | ||
using UnityDataTools.FileSystem; | ||
|
||
namespace UnityDataTools.Analyzer; | ||
|
@@ -11,6 +16,12 @@ public class AnalyzerTool | |
{ | ||
bool m_Verbose = false; | ||
|
||
public List<ISQLiteFileParser> parsers = new List<ISQLiteFileParser>() | ||
{ | ||
new AddressablesBuildLayoutParser(), | ||
new SerializedFileParser(), | ||
}; | ||
|
||
public int Analyze( | ||
string path, | ||
string databaseName, | ||
|
@@ -21,11 +32,19 @@ public int Analyze( | |
{ | ||
m_Verbose = verbose; | ||
|
||
using SQLiteWriter writer = new (databaseName, skipReferences); | ||
// TODO: skipReferences needs to be passed into AssetBundleWriter | ||
using SQLiteWriter writer = new (databaseName); | ||
|
||
try | ||
{ | ||
writer.Begin(); | ||
foreach (var parser in parsers) | ||
{ | ||
parser.Verbose = verbose; | ||
parser.SkipReferences = skipReferences; | ||
parser.Init(writer.Connection); | ||
|
||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
|
@@ -47,31 +66,54 @@ public int Analyze( | |
int i = 1; | ||
foreach (var file in files) | ||
{ | ||
if (ShouldIgnoreFile(file)) | ||
bool foundParser = false; | ||
foreach(var parser in parsers) | ||
{ | ||
if (parser.CanParse(file)) | ||
{ | ||
foundParser = true; | ||
Console.Error.WriteLine(file); | ||
try | ||
{ | ||
parser.Parse(file); | ||
ReportProgress(Path.GetRelativePath(path, file), i, files.Length); | ||
countSuccess++; | ||
} | ||
catch (Exception e) | ||
{ | ||
EraseProgressLine(); | ||
Console.Error.WriteLine(); | ||
Console.Error.WriteLine($"Error processing file: {file}"); | ||
Console.WriteLine($"{e.GetType()}: {e.Message}"); | ||
if (m_Verbose) | ||
Console.WriteLine(e.StackTrace); | ||
countFailures++; | ||
} | ||
++i; | ||
} | ||
} | ||
if (!foundParser) | ||
{ | ||
if (m_Verbose) | ||
{ | ||
var relativePath = Path.GetRelativePath(path, file); | ||
Console.WriteLine(); | ||
Console.WriteLine($"Ignoring {relativePath}"); | ||
} | ||
++i; | ||
countIgnored++; | ||
continue; | ||
} | ||
else if (!ProcessFile(file, path, writer, i, files.Length)) | ||
{ | ||
countFailures++; | ||
} | ||
else | ||
{ | ||
countSuccess++; | ||
} | ||
++i; | ||
} | ||
|
||
Console.WriteLine(); | ||
Console.WriteLine($"Finalizing database. Successfully processed files: {countSuccess}, Failed files: {countFailures}, Ignored files: {countIgnored}"); | ||
|
||
writer.End(); | ||
foreach (var parser in parsers) | ||
{ | ||
parser.Dispose(); | ||
} | ||
|
||
timer.Stop(); | ||
Console.WriteLine(); | ||
|
@@ -80,158 +122,11 @@ public int Analyze( | |
return 0; | ||
} | ||
|
||
bool ShouldIgnoreFile(string file) | ||
{ | ||
// Unfortunately there is no standard extension for AssetBundles, and SerializedFiles often have no extension at all. | ||
// Also there is also no distinctive signature at the start of a SerializedFile to immediately recognize it based on its first bytes. | ||
// This makes it difficult to use the "--search-pattern" argument to only pick those files. | ||
|
||
// Hence to reduce noise in UnityDataTool output we filter out files that we have a high confidence are | ||
// NOT SerializedFiles or Unity Archives. | ||
|
||
string fileName = Path.GetFileName(file); | ||
string extension = Path.GetExtension(file); | ||
|
||
return IgnoredFileNames.Contains(fileName) || IgnoredExtensions.Contains(extension); | ||
} | ||
|
||
// These lists are based on expected output files in Player, AssetBundle, Addressables and ECS builds. | ||
// However this is by no means exhaustive. | ||
private static readonly HashSet<string> IgnoredFileNames = new() | ||
{ | ||
".DS_Store", "boot.config", "archive_dependencies.bin", "scene_info.bin", "app.info", "link.xml", | ||
"catalog.bin", "catalog.hash" | ||
}; | ||
|
||
private static readonly HashSet<string> IgnoredExtensions = new() | ||
{ | ||
".txt", ".resS", ".resource", ".json", ".dll", ".pdb", ".exe", ".manifest", ".entities", ".entityheader", | ||
".ini", ".config" | ||
}; | ||
|
||
bool ProcessFile(string file, string rootDirectory, SQLiteWriter writer, int fileIndex, int cntFiles) | ||
{ | ||
bool successful = true; | ||
try | ||
{ | ||
if (IsUnityArchive(file)) | ||
{ | ||
using (UnityArchive archive = UnityFileSystem.MountArchive(file, "archive:" + Path.DirectorySeparatorChar)) | ||
{ | ||
if (archive == null) | ||
throw new FileLoadException($"Failed to mount archive: {file}"); | ||
|
||
try | ||
{ | ||
var assetBundleName = Path.GetRelativePath(rootDirectory, file); | ||
|
||
writer.BeginAssetBundle(assetBundleName, new FileInfo(file).Length); | ||
ReportProgress(assetBundleName, fileIndex, cntFiles); | ||
|
||
foreach (var node in archive.Nodes) | ||
{ | ||
if (node.Flags.HasFlag(ArchiveNodeFlags.SerializedFile)) | ||
{ | ||
try | ||
{ | ||
writer.WriteSerializedFile(node.Path, "archive:/" + node.Path, Path.GetDirectoryName(file)); | ||
} | ||
catch (Exception e) | ||
{ | ||
// the most likely exception here is Microsoft.Data.Sqlite.SqliteException, | ||
// for example 'UNIQUE constraint failed: serialized_files.id'. | ||
// or 'UNIQUE constraint failed: objects.id' which can happen | ||
// if AssetBundles from different builds are being processed by a single call to Analyze | ||
// or if there is a Unity Data Tool bug. | ||
EraseProgressLine(); | ||
Console.Error.WriteLine($"Error processing {node.Path} in archive {file}"); | ||
Console.Error.WriteLine(e.Message); | ||
Console.WriteLine(); | ||
|
||
// It is possible some files inside an archive will pass and others will fail, to have a partial analyze. | ||
// Overall that is reported as a failure | ||
successful = false; | ||
} | ||
} | ||
} | ||
} | ||
finally | ||
{ | ||
writer.EndAssetBundle(); | ||
} | ||
} | ||
} | ||
else | ||
{ | ||
// This isn't a Unity Archive file. Try to open it as a SerializedFile. | ||
// Unfortunately there is no standard file extension, or clear signature at the start of the file, | ||
// to test if it truly is a SerializedFile. So this will process files that are clearly not unity build files, | ||
// and there is a chance for crashes and freezes if the parser misinterprets the file content. | ||
var relativePath = Path.GetRelativePath(rootDirectory, file); | ||
writer.WriteSerializedFile(relativePath, file, Path.GetDirectoryName(file)); | ||
|
||
ReportProgress(relativePath, fileIndex, cntFiles); | ||
} | ||
|
||
EraseProgressLine(); | ||
} | ||
catch (NotSupportedException) | ||
{ | ||
EraseProgressLine(); | ||
Console.Error.WriteLine(); | ||
//A "failed to load" error will already be logged by the UnityFileSystem library | ||
|
||
successful = false; | ||
} | ||
catch (Exception e) | ||
{ | ||
EraseProgressLine(); | ||
Console.Error.WriteLine(); | ||
Console.Error.WriteLine($"Error processing file: {file}"); | ||
Console.WriteLine($"{e.GetType()}: {e.Message}"); | ||
if (m_Verbose) | ||
Console.WriteLine(e.StackTrace); | ||
|
||
successful = false; | ||
} | ||
|
||
return successful; | ||
} | ||
|
||
private static bool IsUnityArchive(string filePath) | ||
private bool ProcessFile(string file, string path, SQLiteWriter writer, int i, int length) | ||
{ | ||
// Check whether a file is a Unity Archive (AssetBundle) by looking for known signatures at the start of the file. | ||
// "UnifyFS" is the current signature, but some older formats of the file are still supported | ||
string[] signatures = { "UnityFS", "UnityWeb", "UnityRaw", "UnityArchive" }; | ||
int maxLen = 12; // "UnityArchive".Length | ||
byte[] buffer = new byte[maxLen]; | ||
|
||
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) | ||
{ | ||
int read = fs.Read(buffer, 0, buffer.Length); | ||
foreach (var sig in signatures) | ||
{ | ||
if (read >= sig.Length) | ||
{ | ||
bool match = true; | ||
for (int i = 0; i < sig.Length; ++i) | ||
{ | ||
if (buffer[i] != sig[i]) | ||
{ | ||
match = false; | ||
break; | ||
} | ||
} | ||
if (match) | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
throw new NotImplementedException(); | ||
} | ||
Comment on lines
+125
to
128
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dead code should be removed. This method is no longer used after the refactoring to the parser architecture. Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||
|
||
|
||
|
||
int m_LastProgressMessageLength = 0; | ||
|
||
void ReportProgress(string relativePath, int fileIndex, int cntFiles) | ||
|
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debug output should be conditional on verbose mode or removed before production. This will clutter output for every processed file.
Copilot uses AI. Check for mistakes.