diff --git a/.gitignore b/.gitignore index aa59e68..d4d2a12 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,6 @@ UnityFileSystemTestData/**/*.sln UnityFileSystemTestData/ProjectSettings/ UnityFileSystemTestData/UserSettings/ UnityFileSystemTestData/Packages/ +*.db +*.txt +*.csv diff --git a/Analyzer/Analyzer.csproj b/Analyzer/Analyzer.csproj index ac217d0..e3281f7 100644 --- a/Analyzer/Analyzer.csproj +++ b/Analyzer/Analyzer.csproj @@ -1,4 +1,4 @@ - + net9.0 @@ -15,8 +15,13 @@ + + + + + diff --git a/Analyzer/AnalyzerTool.cs b/Analyzer/AnalyzerTool.cs index a293b41..154a42f 100644 --- a/Analyzer/AnalyzerTool.cs +++ b/Analyzer/AnalyzerTool.cs @@ -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 parsers = new List() + { + 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,7 +66,33 @@ 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) { @@ -55,23 +100,20 @@ public int Analyze( 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 IgnoredFileNames = new() - { - ".DS_Store", "boot.config", "archive_dependencies.bin", "scene_info.bin", "app.info", "link.xml", - "catalog.bin", "catalog.hash" - }; - - private static readonly HashSet 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(); } - - int m_LastProgressMessageLength = 0; void ReportProgress(string relativePath, int fileIndex, int cntFiles) diff --git a/Analyzer/Build/BuildLayout.cs b/Analyzer/Build/BuildLayout.cs new file mode 100644 index 0000000..5361326 --- /dev/null +++ b/Analyzer/Build/BuildLayout.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Numerics; + +namespace UnityDataTools.Analyzer.Build +{ + public class BuildLayout + { + /// + /// Build Platform Addressables build is targeting + /// + public int BuildTarget; + + /// + /// Hash of the build results + /// + public string BuildResultHash; + + /// + /// If the build was a new build or an update for a previous build + /// + public int BuildType; + + /// + /// DateTime at the start of building Addressables + /// + public string BuildStartTime; + + /// + /// Time in seconds taken to build Addressables Content + /// + public double Duration; + + /// + /// Null or Empty if the build completed successfully, else contains error causing the failure + /// + public string BuildError; + + /// + /// Version of the Unity edtior used to perform the build. + /// + public string UnityVersion; + + /// + /// Version of the Addressables package used to perform the build. + /// + public string PackageVersion; + + /// + /// Player build version for the build, this is a timestamp if PlayerVersionOverride is not set in the settings + /// + public string PlayerBuildVersion; + + /// + /// Name of the build script to build + /// + public string BuildScript; + + public References references; + + } + + public class References + { + public List RefIds = new(); + } + + public class ReferenceId + { + public int rid; + } + + public class Reference : ReferenceId + { + public ReferenceData data; + + public ReferenceType type; + } + + public class ReferenceData + { + public ReferenceId Bundle; + public ReferenceId File; + public AssetHash AssetHash; + public string AssetPath; + public string AddressableName; + public string AddressableGuid; + public ReferenceId[] ExternallyReferencedAssets; + public string GroupGuid; + public string Guid; + public string InternalId; + public ReferenceId[] InternalReferencedExplicitAssets; + public ReferenceId[] InternalReferencedOtherAssets; + public string[] Labels; + public int MainAssetType; + public int StreamedSize; + public int SerializedSize; + public string Name; + public string CRC; + + // For BuildLayout/Bundle + public int AssetCount; + public int BuildStatus; + public ReferenceId[] BundleDependencies; + public string Compression; + public ReferenceId[] Dependencies; + public int DependencyFileSize; + public ReferenceId[] DependentBundles; + public ReferenceId[] ExpandedDependencies; + public int ExpandedDependencyFileSize; + public int FileSize; + public ReferenceId[] Files; + public ReferenceId Group; + public object Hash; // Complex object containing Hash and serializedVersion + public string InternalName; + public string LoadPath; + public string Provider; + public string ResultType; + + // For BuildLayout/DataFromOtherAsset + public string AssetGuid; + public int ObjectCount; + public AssetObject[] Objects; // Array of object data + public ReferenceId[] ReferencingAssets; + + // For BuildLayout/File + public ReferenceId[] Assets; + public BundleObjectInfo BundleObjectInfo; // Object with Size property + public ReferenceId[] ExternalReferences; + public int MonoScriptCount; + public int MonoScriptSize; + public ReferenceId[] OtherAssets; + public int PreloadInfoSize; + public ReferenceId[] SubFiles; + public string WriteResultFilename; + + // For BuildLayout/Group + public ReferenceId[] Bundles; + public string PackingMode; + public ReferenceId[] Schemas; + + // For BuildLayout/SchemaData + public SchemaDataPair[] SchemaDataPairs; // Array of Key-Value pairs + public string Type; + + // For BuildLayout/SubFile + public bool IsSerializedFile; + public int Size; + } + + public class ReferenceType + { + public string Asm; + public string Class; + public string NS; + } + + public class AssetHash + { + public string Hash; + public string serializedVersion; + } + + public class BundleObjectInfo + { + public int Size; + } + + public class AssetObject + { + public int AssetType; + public string ComponentName; + public long LocalIdentifierInFile; + public string ObjectName; + public int SerializedSize; + public ObjectReference[] References; // Array of object references + public int StreamedSize; + } + + public class ObjectReference + { + public int AssetId; + public int ObjectId; + } + + public class SchemaDataPair + { + public string Key; + public string Value; + } +} diff --git a/Analyzer/IWriter.cs b/Analyzer/IWriter.cs deleted file mode 100644 index 7700c08..0000000 --- a/Analyzer/IWriter.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityDataTools.Analyzer.SerializedObjects; -using UnityDataTools.FileSystem; - -namespace UnityDataTools.Analyzer; - -public interface IWriter : IDisposable -{ - void Begin(); - void BeginAssetBundle(string name, long size); - void EndAssetBundle(); - void WriteSerializedFile(string relativePath, string fullPath, string containingFolder); - void End(); -} diff --git a/Analyzer/Properties/Resources.Designer.cs b/Analyzer/Properties/Resources.Designer.cs index 487a20a..963ed8b 100644 --- a/Analyzer/Properties/Resources.Designer.cs +++ b/Analyzer/Properties/Resources.Designer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -namespace UnityDataTools.Analyzer.Properties { +namespace Analyzer.Properties { using System; @@ -19,7 +19,7 @@ namespace UnityDataTools.Analyzer.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -60,6 +60,487 @@ internal Resources() { } } + /// + /// Looks up a localized string similar to create table addr_build_bundle_dependencies + ///( + /// bundle_id INTEGER, + /// build_id INTEGER, + /// dependency_rid INTEGER, + /// PRIMARY KEY (bundle_id, build_id, dependency_rid), + /// FOREIGN KEY (bundle_id, build_id) REFERENCES addr_build_bundles(id, build_id) + ///);. + /// + internal static string AddrBuildBundleDependencies { + get { + return ResourceManager.GetString("AddrBuildBundleDependencies", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_bundle_dependent_bundles + ///( + /// bundle_id INTEGER, + /// build_id INTEGER, + /// dependent_bundle_rid INTEGER, + /// PRIMARY KEY (bundle_id, build_id, dependent_bundle_rid), + /// FOREIGN KEY (bundle_id, build_id) REFERENCES addr_build_bundles(id, build_id) + ///);. + /// + internal static string AddrBuildBundleDependentBundles { + get { + return ResourceManager.GetString("AddrBuildBundleDependentBundles", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_bundle_expanded_dependencies + ///( + /// bundle_id INTEGER, + /// build_id INTEGER, + /// dependency_rid INTEGER, + /// PRIMARY KEY (bundle_id, build_id, dependency_rid), + /// FOREIGN KEY (bundle_id, build_id) REFERENCES addr_build_bundles(id, build_id) + ///);. + /// + internal static string AddrBuildBundleExpandedDependencies { + get { + return ResourceManager.GetString("AddrBuildBundleExpandedDependencies", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_bundle_files + ///( + /// bundle_id INTEGER, + /// build_id INTEGER, + /// file_rid INTEGER, + /// PRIMARY KEY (bundle_id, build_id, file_rid), + /// FOREIGN KEY (bundle_id, build_id) REFERENCES addr_build_bundles(id, build_id) + ///);. + /// + internal static string AddrBuildBundleFiles { + get { + return ResourceManager.GetString("AddrBuildBundleFiles", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_bundle_regular_dependencies + ///( + /// bundle_id INTEGER, + /// build_id INTEGER, + /// dependency_rid INTEGER, + /// PRIMARY KEY (bundle_id, build_id, dependency_rid), + /// FOREIGN KEY (bundle_id, build_id) REFERENCES addr_build_bundles(id, build_id) + ///);. + /// + internal static string AddrBuildBundleRegularDependencies { + get { + return ResourceManager.GetString("AddrBuildBundleRegularDependencies", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_bundles + ///( + /// id INTEGER, + /// build_id INTEGER, + /// asset_count INTEGER, + /// build_status INTEGER, + /// crc INTEGER, + /// compression TEXT, + /// dependency_file_size INTEGER, + /// expanded_dependency_file_size INTEGER, + /// file_size INTEGER, + /// group_rid INTEGER, + /// hash TEXT, + /// internal_name TEXT, + /// load_path TEXT, + /// name TEXT, + /// provider TEXT, + /// result_type TEXT, + /// PRIMARY KEY (id, build_id) + ///);. + /// + internal static string AddrBuildBundles { + get { + return ResourceManager.GetString("AddrBuildBundles", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_data_from_other_asset_object_references + ///( + /// data_from_other_asset_id INTEGER, + /// build_id INTEGER, + /// local_identifier_in_file INTEGER, + /// asset_id INTEGER, + /// object_id INTEGER, + /// PRIMARY KEY (data_from_other_asset_id, build_id, local_identifier_in_file, asset_id, object_id), + /// FOREIGN KEY (data_from_other_asset_id, build_id, local_identifier_in_file) REFERENCES addr_build_data_from_other_asset_objects(data_from_other_asset_id, build_id, local_identifier_in_file) + /// [rest of string was truncated]";. + /// + internal static string AddrBuildDataFromOtherAssetObjectReferences { + get { + return ResourceManager.GetString("AddrBuildDataFromOtherAssetObjectReferences", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_data_from_other_asset_objects + ///( + /// data_from_other_asset_id INTEGER, + /// build_id INTEGER, + /// asset_type INTEGER, + /// component_name TEXT, + /// local_identifier_in_file INTEGER, + /// object_name TEXT, + /// serialized_size INTEGER, + /// streamed_size INTEGER, + /// PRIMARY KEY (data_from_other_asset_id, build_id, local_identifier_in_file), + /// FOREIGN KEY (data_from_other_asset_id, build_id) REFERENCES addr_build_data_from_other_assets(id, build_id) + ///);. + /// + internal static string AddrBuildDataFromOtherAssetObjects { + get { + return ResourceManager.GetString("AddrBuildDataFromOtherAssetObjects", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_data_from_other_asset_referencing_assets + ///( + /// data_from_other_asset_id INTEGER, + /// build_id INTEGER, + /// referencing_asset_rid INTEGER, + /// PRIMARY KEY (data_from_other_asset_id, build_id, referencing_asset_rid), + /// FOREIGN KEY (data_from_other_asset_id, build_id) REFERENCES addr_build_data_from_other_assets(id, build_id) + ///);. + /// + internal static string AddrBuildDataFromOtherAssetReferencingAssets { + get { + return ResourceManager.GetString("AddrBuildDataFromOtherAssetReferencingAssets", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_data_from_other_assets + ///( + /// id INTEGER, + /// build_id INTEGER, + /// asset_guid TEXT, + /// asset_path TEXT, + /// file INTEGER, + /// main_asset_type INTEGER, + /// object_count INTEGER, + /// serialized_size INTEGER, + /// streamed_size INTEGER, + /// PRIMARY KEY (id, build_id) + ///);. + /// + internal static string AddrBuildDataFromOtherAssets { + get { + return ResourceManager.GetString("AddrBuildDataFromOtherAssets", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_explicit_asset_externally_referenced_assets + ///( + /// explicit_asset_id INTEGER, + /// build_id INTEGER, + /// externally_referenced_asset_rid INTEGER, + /// PRIMARY KEY (explicit_asset_id, build_id, externally_referenced_asset_rid), + /// FOREIGN KEY (explicit_asset_id, build_id) REFERENCES addr_build_explicit_assets(id, build_id) + ///);. + /// + internal static string AddrBuildExplicitAssetExternallyReferencedAssets { + get { + return ResourceManager.GetString("AddrBuildExplicitAssetExternallyReferencedAssets", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_explicit_asset_internal_referenced_explicit_assets + ///( + /// explicit_asset_id INTEGER, + /// build_id INTEGER, + /// internal_referenced_explicit_asset_rid INTEGER, + /// PRIMARY KEY (explicit_asset_id, build_id, internal_referenced_explicit_asset_rid), + /// FOREIGN KEY (explicit_asset_id, build_id) REFERENCES addr_build_explicit_assets(id, build_id) + ///);. + /// + internal static string AddrBuildExplicitAssetInternalReferencedExplicitAssets { + get { + return ResourceManager.GetString("AddrBuildExplicitAssetInternalReferencedExplicitAssets", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_explicit_asset_internal_referenced_other_assets + ///( + /// explicit_asset_id INTEGER, + /// build_id INTEGER, + /// internal_referenced_other_asset_rid INTEGER, + /// PRIMARY KEY (explicit_asset_id, build_id, internal_referenced_other_asset_rid), + /// FOREIGN KEY (explicit_asset_id, build_id) REFERENCES addr_build_explicit_assets(id, build_id) + ///);. + /// + internal static string AddrBuildExplicitAssetInternalReferencedOtherAssets { + get { + return ResourceManager.GetString("AddrBuildExplicitAssetInternalReferencedOtherAssets", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_explicit_asset_labels + ///( + /// explicit_asset_id INTEGER, + /// build_id INTEGER, + /// label TEXT, + /// PRIMARY KEY (explicit_asset_id, build_id, label), + /// FOREIGN KEY (explicit_asset_id, build_id) REFERENCES addr_build_explicit_assets(id, build_id) + ///);. + /// + internal static string AddrBuildExplicitAssetLabels { + get { + return ResourceManager.GetString("AddrBuildExplicitAssetLabels", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_explicit_assets + ///( + /// id INTEGER, + /// build_id INTEGER, + /// bundle INTEGER, + /// file INTEGER, + /// asset_hash TEXT, + /// asset_path TEXT, + /// addressable_name TEXT, + /// group_guid TEXT, + /// guid TEXT, + /// internal_id TEXT, + /// main_asset_type INTEGER, + /// serialized_size INTEGER, + /// streamed_size INTEGER, + /// PRIMARY KEY (id, build_id) + ///);. + /// + internal static string AddrBuildExplicitAssets { + get { + return ResourceManager.GetString("AddrBuildExplicitAssets", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_file_assets + ///( + /// file_id INTEGER, + /// build_id INTEGER, + /// asset_rid INTEGER, + /// PRIMARY KEY (file_id, build_id, asset_rid), + /// FOREIGN KEY (file_id, build_id) REFERENCES addr_build_files(id, build_id) + ///);. + /// + internal static string AddrBuildFileAssets { + get { + return ResourceManager.GetString("AddrBuildFileAssets", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_file_external_references + ///( + /// file_id INTEGER, + /// build_id INTEGER, + /// external_reference_rid INTEGER, + /// PRIMARY KEY (file_id, build_id, external_reference_rid), + /// FOREIGN KEY (file_id, build_id) REFERENCES addr_build_files(id, build_id) + ///);. + /// + internal static string AddrBuildFileExternalReferences { + get { + return ResourceManager.GetString("AddrBuildFileExternalReferences", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_file_other_assets + ///( + /// file_id INTEGER, + /// build_id INTEGER, + /// other_asset_rid INTEGER, + /// PRIMARY KEY (file_id, build_id, other_asset_rid), + /// FOREIGN KEY (file_id, build_id) REFERENCES addr_build_files(id, build_id) + ///);. + /// + internal static string AddrBuildFileOtherAssets { + get { + return ResourceManager.GetString("AddrBuildFileOtherAssets", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_files + ///( + /// id INTEGER, + /// build_id INTEGER, + /// bundle INTEGER, + /// bundle_object_info_size INTEGER, + /// mono_script_count INTEGER, + /// mono_script_size INTEGER, + /// name TEXT, + /// preload_info_size INTEGER, + /// write_result_filename TEXT, + /// PRIMARY KEY (id, build_id) + ///);. + /// + internal static string AddrBuildFiles { + get { + return ResourceManager.GetString("AddrBuildFiles", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_file_sub_files + ///( + /// file_id INTEGER, + /// build_id INTEGER, + /// sub_file_rid INTEGER, + /// PRIMARY KEY (file_id, build_id, sub_file_rid), + /// FOREIGN KEY (file_id, build_id) REFERENCES addr_build_files(id, build_id) + ///);. + /// + internal static string AddrBuildFileSubFiles { + get { + return ResourceManager.GetString("AddrBuildFileSubFiles", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_group_bundles + ///( + /// group_id INTEGER, + /// build_id INTEGER, + /// bundle_rid INTEGER, + /// PRIMARY KEY (group_id, build_id, bundle_rid), + /// FOREIGN KEY (group_id, build_id) REFERENCES addr_build_groups(id, build_id) + ///);. + /// + internal static string AddrBuildGroupBundles { + get { + return ResourceManager.GetString("AddrBuildGroupBundles", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_groups + ///( + /// id INTEGER, + /// build_id INTEGER, + /// guid TEXT, + /// name TEXT, + /// packing_mode TEXT, + /// PRIMARY KEY (id, build_id) + ///);. + /// + internal static string AddrBuildGroups { + get { + return ResourceManager.GetString("AddrBuildGroups", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_group_schemas + ///( + /// group_id INTEGER, + /// build_id INTEGER, + /// schema_rid INTEGER, + /// PRIMARY KEY (group_id, build_id, schema_rid), + /// FOREIGN KEY (group_id, build_id) REFERENCES addr_build_groups(id, build_id) + ///);. + /// + internal static string AddrBuildGroupSchemas { + get { + return ResourceManager.GetString("AddrBuildGroupSchemas", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CREATE TABLE addr_builds + ///( + /// id INTEGER, + /// name TEXT, + /// build_target INTEGER, + /// start_time TEXT, + /// duration REAL, + /// error TEXT, + /// package_version TEXT, + /// player_version TEXT, + /// build_script TEXT, + /// result_hash TEXT, + /// type INTEGER, + /// unity_version TEXT, + /// PRIMARY KEY (id) + ///);. + /// + internal static string AddrBuilds { + get { + return ResourceManager.GetString("AddrBuilds", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_schema_data_pairs + ///( + /// schema_id INTEGER, + /// build_id INTEGER, + /// key TEXT, + /// value TEXT, + /// PRIMARY KEY (schema_id, build_id, key), + /// FOREIGN KEY (schema_id, build_id) REFERENCES addr_build_schemas(id, build_id) + ///);. + /// + internal static string AddrBuildSchemaDataPairs { + get { + return ResourceManager.GetString("AddrBuildSchemaDataPairs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_schemas + ///( + /// id INTEGER, + /// build_id INTEGER, + /// guid TEXT, + /// type TEXT, + /// PRIMARY KEY (id, build_id) + ///);. + /// + internal static string AddrBuildSchemas { + get { + return ResourceManager.GetString("AddrBuildSchemas", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to create table addr_build_sub_files + ///( + /// id INTEGER, + /// build_id INTEGER, + /// is_serialized_file INTEGER, + /// name TEXT, + /// size INTEGER, + /// PRIMARY KEY (id, build_id) + ///);. + /// + internal static string AddrBuildSubFiles { + get { + return ResourceManager.GetString("AddrBuildSubFiles", resourceCulture); + } + } + /// /// Looks up a localized string similar to CREATE TABLE animation_clips( /// id INTEGER, @@ -88,12 +569,21 @@ internal static string AnimationClip { /// name TEXT ///); /// + ///CREATE TABLE asset_dependencies( + /// object INTEGER, + /// dependency INTEGER + ///); + /// ///CREATE VIEW asset_view AS ///SELECT /// a.name AS asset_name, /// o.* ///FROM assets a INNER JOIN object_view o ON o.id = a.object; - ///. + /// + ///CREATE VIEW asset_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 [rest of string was truncated]";. /// internal static string AssetBundle { get { @@ -183,7 +673,7 @@ internal static string Finalize { /// name TEXT, /// game_object INTEGER, /// size INTEGER, - /// PRIMARY KE [rest of string was truncated]";. + /// crc32 INTE [rest of string was truncated]";. /// internal static string Init { get { @@ -201,6 +691,8 @@ internal static string Init { /// vertices INTEGER, /// compression INTEGER, /// rw_enabled INTEGER, + /// vertex_size INTEGER, + /// channels TEXT, /// PRIMARY KEY (id) ///); /// @@ -213,10 +705,11 @@ internal static string Init { /// m.indices, /// m.vertices, /// m.compression, - /// m.rw_enabled + /// m.rw_enabled, + /// m.vertex_size, + /// m.channels ///FROM meshes m - ///INNER JOIN object_view o ON o.id = m.id; - ///. + ///INNER JOIN [rest of string was truncated]";. /// internal static string Mesh { get { @@ -228,12 +721,21 @@ internal static string Mesh { /// Looks up a localized string similar to CREATE TABLE shaders( /// id INTEGER, /// decompressed_size INTEGER, - /// sub_shaders INTEGER, /// unique_programs INTEGER, - /// keywords TEXT, /// PRIMARY KEY (id) ///); /// + ///CREATE TABLE shader_keywords( + /// id INTEGER, + /// keyword TEXT, + /// PRIMARY KEY (id) + ///); + /// + ///CREATE TABLE shader_subprogram_keywords( + /// subprogram_id INTEGER, + /// keyword_id INTEGER + ///); + /// ///CREATE TABLE shader_apis( /// id INTEGER, /// name TEXT, @@ -241,19 +743,10 @@ internal static string Mesh { ///); /// ///CREATE TABLE shader_subprograms( + /// id INTEGER, /// shader INTEGER, - /// pass INTEGER, - /// sub_program INTEGER, - /// hw_tier INTEGER, - /// shader_type TEXT, - /// api INTEGER, - /// keywords TEXT - ///); - /// - ///CREATE VIEW shader_view AS - ///SELECT - /// o.*, - /// s.decompre [rest of string was truncated]";. + /// sub_shader INTEGER, + /// [rest of string was truncated]";. /// internal static string Shader { get { diff --git a/Analyzer/Properties/Resources.resx b/Analyzer/Properties/Resources.resx index 1144559..138b62d 100644 --- a/Analyzer/Properties/Resources.resx +++ b/Analyzer/Properties/Resources.resx @@ -142,4 +142,86 @@ ..\Resources\Texture2D.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - \ No newline at end of file + + ..\Resources\AddrBuilds.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildBundles.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildBundleDependentBundles.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildBundleDependencies.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildBundleExpandedDependencies.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildBundleFiles.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildBundleRegularDependencies.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildDataFromOtherAssets.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildDataFromOtherAssetObjects.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildDataFromOtherAssetObjectReferences.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildDataFromOtherAssetReferencingAssets.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildExplicitAssets.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildExplicitAssetExternallyReferencedAssets.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildExplicitAssetInternalReferencedExplicitAssets.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildExplicitAssetInternalReferencedOtherAssets.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildExplicitAssetLabels.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildFiles.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildFileAssets.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildFileOtherAssets.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildFileSubFiles.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildFileExternalReferences.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildGroupBundles.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + + ..\Resources\AddrBuildGroups.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildGroupSchemas.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildSchemas.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildSubFiles.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Resources\AddrBuildSchemaDataPairs.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + diff --git a/Analyzer/Resources/AddrBuildBundleDependencies.sql b/Analyzer/Resources/AddrBuildBundleDependencies.sql new file mode 100644 index 0000000..3bfdc4d --- /dev/null +++ b/Analyzer/Resources/AddrBuildBundleDependencies.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_bundle_dependencies +( + bundle_id INTEGER, + build_id INTEGER, + dependency_rid INTEGER, + PRIMARY KEY (bundle_id, build_id, dependency_rid), + FOREIGN KEY (bundle_id, build_id) REFERENCES addr_build_bundles(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildBundleDependentBundles.sql b/Analyzer/Resources/AddrBuildBundleDependentBundles.sql new file mode 100644 index 0000000..a4ab5e0 --- /dev/null +++ b/Analyzer/Resources/AddrBuildBundleDependentBundles.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_bundle_dependent_bundles +( + bundle_id INTEGER, + build_id INTEGER, + dependent_bundle_rid INTEGER, + PRIMARY KEY (bundle_id, build_id, dependent_bundle_rid), + FOREIGN KEY (bundle_id, build_id) REFERENCES addr_build_bundles(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildBundleExpandedDependencies.sql b/Analyzer/Resources/AddrBuildBundleExpandedDependencies.sql new file mode 100644 index 0000000..432847c --- /dev/null +++ b/Analyzer/Resources/AddrBuildBundleExpandedDependencies.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_bundle_expanded_dependencies +( + bundle_id INTEGER, + build_id INTEGER, + dependency_rid INTEGER, + PRIMARY KEY (bundle_id, build_id, dependency_rid), + FOREIGN KEY (bundle_id, build_id) REFERENCES addr_build_bundles(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildBundleFiles.sql b/Analyzer/Resources/AddrBuildBundleFiles.sql new file mode 100644 index 0000000..06b66bf --- /dev/null +++ b/Analyzer/Resources/AddrBuildBundleFiles.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_bundle_files +( + bundle_id INTEGER, + build_id INTEGER, + file_rid INTEGER, + PRIMARY KEY (bundle_id, build_id, file_rid), + FOREIGN KEY (bundle_id, build_id) REFERENCES addr_build_bundles(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildBundleRegularDependencies.sql b/Analyzer/Resources/AddrBuildBundleRegularDependencies.sql new file mode 100644 index 0000000..a115ade --- /dev/null +++ b/Analyzer/Resources/AddrBuildBundleRegularDependencies.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_bundle_regular_dependencies +( + bundle_id INTEGER, + build_id INTEGER, + dependency_rid INTEGER, + PRIMARY KEY (bundle_id, build_id, dependency_rid), + FOREIGN KEY (bundle_id, build_id) REFERENCES addr_build_bundles(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildBundles.sql b/Analyzer/Resources/AddrBuildBundles.sql new file mode 100644 index 0000000..d0cefa2 --- /dev/null +++ b/Analyzer/Resources/AddrBuildBundles.sql @@ -0,0 +1,22 @@ +CREATE TABLE IF NOT EXISTS addr_build_bundles +( + id INTEGER, + build_id INTEGER, + asset_count INTEGER, + build_status INTEGER, + crc INTEGER, + compression TEXT, + dependency_file_size INTEGER, + expanded_dependency_file_size INTEGER, + file_size INTEGER, + group_rid INTEGER, + hash TEXT, + internal_name TEXT, + load_path TEXT, + name TEXT, + provider TEXT, + result_type TEXT, + PRIMARY KEY (id, build_id) +); + +CREATE VIEW IF NOT EXISTS addr_build_cached_bundles AS SELECT build_id, concat(internal_name, '.bundle') AS cached_name, name AS catalog_name FROM addr_build_bundles; diff --git a/Analyzer/Resources/AddrBuildDataFromOtherAssetObjectReferences.sql b/Analyzer/Resources/AddrBuildDataFromOtherAssetObjectReferences.sql new file mode 100644 index 0000000..db8b6cb --- /dev/null +++ b/Analyzer/Resources/AddrBuildDataFromOtherAssetObjectReferences.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS addr_build_data_from_other_asset_object_references +( + data_from_other_asset_id INTEGER, + build_id INTEGER, + local_identifier_in_file INTEGER, + asset_id INTEGER, + object_id INTEGER, + PRIMARY KEY (data_from_other_asset_id, build_id, local_identifier_in_file, asset_id, object_id), + FOREIGN KEY (data_from_other_asset_id, build_id, local_identifier_in_file) REFERENCES addr_build_data_from_other_asset_objects(data_from_other_asset_id, build_id, local_identifier_in_file) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildDataFromOtherAssetObjects.sql b/Analyzer/Resources/AddrBuildDataFromOtherAssetObjects.sql new file mode 100644 index 0000000..75c7771 --- /dev/null +++ b/Analyzer/Resources/AddrBuildDataFromOtherAssetObjects.sql @@ -0,0 +1,13 @@ +CREATE TABLE IF NOT EXISTS addr_build_data_from_other_asset_objects +( + data_from_other_asset_id INTEGER, + build_id INTEGER, + asset_type INTEGER, + component_name TEXT, + local_identifier_in_file INTEGER, + object_name TEXT, + serialized_size INTEGER, + streamed_size INTEGER, + PRIMARY KEY (data_from_other_asset_id, build_id, local_identifier_in_file), + FOREIGN KEY (data_from_other_asset_id, build_id) REFERENCES addr_build_data_from_other_assets(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildDataFromOtherAssetReferencingAssets.sql b/Analyzer/Resources/AddrBuildDataFromOtherAssetReferencingAssets.sql new file mode 100644 index 0000000..3d601d0 --- /dev/null +++ b/Analyzer/Resources/AddrBuildDataFromOtherAssetReferencingAssets.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_data_from_other_asset_referencing_assets +( + data_from_other_asset_id INTEGER, + build_id INTEGER, + referencing_asset_rid INTEGER, + PRIMARY KEY (data_from_other_asset_id, build_id, referencing_asset_rid), + FOREIGN KEY (data_from_other_asset_id, build_id) REFERENCES addr_build_data_from_other_assets(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildDataFromOtherAssets.sql b/Analyzer/Resources/AddrBuildDataFromOtherAssets.sql new file mode 100644 index 0000000..8eb289c --- /dev/null +++ b/Analyzer/Resources/AddrBuildDataFromOtherAssets.sql @@ -0,0 +1,13 @@ +CREATE TABLE IF NOT EXISTS addr_build_data_from_other_assets +( + id INTEGER, + build_id INTEGER, + asset_guid TEXT, + asset_path TEXT, + file INTEGER, + main_asset_type INTEGER, + object_count INTEGER, + serialized_size INTEGER, + streamed_size INTEGER, + PRIMARY KEY (id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildExplicitAssetExternallyReferencedAssets.sql b/Analyzer/Resources/AddrBuildExplicitAssetExternallyReferencedAssets.sql new file mode 100644 index 0000000..0d7be69 --- /dev/null +++ b/Analyzer/Resources/AddrBuildExplicitAssetExternallyReferencedAssets.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_explicit_asset_externally_referenced_assets +( + explicit_asset_id INTEGER, + build_id INTEGER, + externally_referenced_asset_rid INTEGER, + PRIMARY KEY (explicit_asset_id, build_id, externally_referenced_asset_rid), + FOREIGN KEY (explicit_asset_id, build_id) REFERENCES addr_build_explicit_assets(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildExplicitAssetInternalReferencedExplicitAssets.sql b/Analyzer/Resources/AddrBuildExplicitAssetInternalReferencedExplicitAssets.sql new file mode 100644 index 0000000..c938f85 --- /dev/null +++ b/Analyzer/Resources/AddrBuildExplicitAssetInternalReferencedExplicitAssets.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_explicit_asset_internal_referenced_explicit_assets +( + explicit_asset_id INTEGER, + build_id INTEGER, + internal_referenced_explicit_asset_rid INTEGER, + PRIMARY KEY (explicit_asset_id, build_id, internal_referenced_explicit_asset_rid), + FOREIGN KEY (explicit_asset_id, build_id) REFERENCES addr_build_explicit_assets(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildExplicitAssetInternalReferencedOtherAssets.sql b/Analyzer/Resources/AddrBuildExplicitAssetInternalReferencedOtherAssets.sql new file mode 100644 index 0000000..fe768f3 --- /dev/null +++ b/Analyzer/Resources/AddrBuildExplicitAssetInternalReferencedOtherAssets.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_explicit_asset_internal_referenced_other_assets +( + explicit_asset_id INTEGER, + build_id INTEGER, + internal_referenced_other_asset_rid INTEGER, + PRIMARY KEY (explicit_asset_id, build_id, internal_referenced_other_asset_rid), + FOREIGN KEY (explicit_asset_id, build_id) REFERENCES addr_build_explicit_assets(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildExplicitAssetLabels.sql b/Analyzer/Resources/AddrBuildExplicitAssetLabels.sql new file mode 100644 index 0000000..0641a4a --- /dev/null +++ b/Analyzer/Resources/AddrBuildExplicitAssetLabels.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_explicit_asset_labels +( + explicit_asset_id INTEGER, + build_id INTEGER, + label TEXT, + PRIMARY KEY (explicit_asset_id, build_id, label), + FOREIGN KEY (explicit_asset_id, build_id) REFERENCES addr_build_explicit_assets(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildExplicitAssets.sql b/Analyzer/Resources/AddrBuildExplicitAssets.sql new file mode 100644 index 0000000..693bbc3 --- /dev/null +++ b/Analyzer/Resources/AddrBuildExplicitAssets.sql @@ -0,0 +1,17 @@ +CREATE TABLE IF NOT EXISTS addr_build_explicit_assets +( + id INTEGER, + build_id INTEGER, + bundle INTEGER, + file INTEGER, + asset_hash TEXT, + asset_path TEXT, + addressable_name TEXT, + group_guid TEXT, + guid TEXT, + internal_id TEXT, + main_asset_type INTEGER, + serialized_size INTEGER, + streamed_size INTEGER, + PRIMARY KEY (id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildFileAssets.sql b/Analyzer/Resources/AddrBuildFileAssets.sql new file mode 100644 index 0000000..0dcfc3e --- /dev/null +++ b/Analyzer/Resources/AddrBuildFileAssets.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_file_assets +( + file_id INTEGER, + build_id INTEGER, + asset_rid INTEGER, + PRIMARY KEY (file_id, build_id, asset_rid), + FOREIGN KEY (file_id, build_id) REFERENCES addr_build_files(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildFileExternalReferences.sql b/Analyzer/Resources/AddrBuildFileExternalReferences.sql new file mode 100644 index 0000000..3ac6cd8 --- /dev/null +++ b/Analyzer/Resources/AddrBuildFileExternalReferences.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_file_external_references +( + file_id INTEGER, + build_id INTEGER, + external_reference_rid INTEGER, + PRIMARY KEY (file_id, build_id, external_reference_rid), + FOREIGN KEY (file_id, build_id) REFERENCES addr_build_files(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildFileOtherAssets.sql b/Analyzer/Resources/AddrBuildFileOtherAssets.sql new file mode 100644 index 0000000..f91b288 --- /dev/null +++ b/Analyzer/Resources/AddrBuildFileOtherAssets.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_file_other_assets +( + file_id INTEGER, + build_id INTEGER, + other_asset_rid INTEGER, + PRIMARY KEY (file_id, build_id, other_asset_rid), + FOREIGN KEY (file_id, build_id) REFERENCES addr_build_files(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildFileSubFiles.sql b/Analyzer/Resources/AddrBuildFileSubFiles.sql new file mode 100644 index 0000000..b228584 --- /dev/null +++ b/Analyzer/Resources/AddrBuildFileSubFiles.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_file_sub_files +( + file_id INTEGER, + build_id INTEGER, + sub_file_rid INTEGER, + PRIMARY KEY (file_id, build_id, sub_file_rid), + FOREIGN KEY (file_id, build_id) REFERENCES addr_build_files(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildFiles.sql b/Analyzer/Resources/AddrBuildFiles.sql new file mode 100644 index 0000000..4a673f1 --- /dev/null +++ b/Analyzer/Resources/AddrBuildFiles.sql @@ -0,0 +1,13 @@ +CREATE TABLE IF NOT EXISTS addr_build_files +( + id INTEGER, + build_id INTEGER, + bundle INTEGER, + bundle_object_info_size INTEGER, + mono_script_count INTEGER, + mono_script_size INTEGER, + name TEXT, + preload_info_size INTEGER, + write_result_filename TEXT, + PRIMARY KEY (id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildGroupBundles.sql b/Analyzer/Resources/AddrBuildGroupBundles.sql new file mode 100644 index 0000000..87996b8 --- /dev/null +++ b/Analyzer/Resources/AddrBuildGroupBundles.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_group_bundles +( + group_id INTEGER, + build_id INTEGER, + bundle_rid INTEGER, + PRIMARY KEY (group_id, build_id, bundle_rid), + FOREIGN KEY (group_id, build_id) REFERENCES addr_build_groups(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildGroupSchemas.sql b/Analyzer/Resources/AddrBuildGroupSchemas.sql new file mode 100644 index 0000000..c3f2ba6 --- /dev/null +++ b/Analyzer/Resources/AddrBuildGroupSchemas.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_group_schemas +( + group_id INTEGER, + build_id INTEGER, + schema_rid INTEGER, + PRIMARY KEY (group_id, build_id, schema_rid), + FOREIGN KEY (group_id, build_id) REFERENCES addr_build_groups(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildGroups.sql b/Analyzer/Resources/AddrBuildGroups.sql new file mode 100644 index 0000000..8a393a7 --- /dev/null +++ b/Analyzer/Resources/AddrBuildGroups.sql @@ -0,0 +1,9 @@ +CREATE TABLE IF NOT EXISTS addr_build_groups +( + id INTEGER, + build_id INTEGER, + guid TEXT, + name TEXT, + packing_mode TEXT, + PRIMARY KEY (id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildSchemaDataPairs.sql b/Analyzer/Resources/AddrBuildSchemaDataPairs.sql new file mode 100644 index 0000000..ac42379 --- /dev/null +++ b/Analyzer/Resources/AddrBuildSchemaDataPairs.sql @@ -0,0 +1,9 @@ +CREATE TABLE IF NOT EXISTS addr_build_schema_data_pairs +( + schema_id INTEGER, + build_id INTEGER, + key TEXT, + value TEXT, + PRIMARY KEY (schema_id, build_id, key), + FOREIGN KEY (schema_id, build_id) REFERENCES addr_build_schemas(id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildSchemas.sql b/Analyzer/Resources/AddrBuildSchemas.sql new file mode 100644 index 0000000..482d6f2 --- /dev/null +++ b/Analyzer/Resources/AddrBuildSchemas.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS addr_build_schemas +( + id INTEGER, + build_id INTEGER, + guid TEXT, + type TEXT, + PRIMARY KEY (id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuildSubFiles.sql b/Analyzer/Resources/AddrBuildSubFiles.sql new file mode 100644 index 0000000..eb38219 --- /dev/null +++ b/Analyzer/Resources/AddrBuildSubFiles.sql @@ -0,0 +1,9 @@ +CREATE TABLE IF NOT EXISTS addr_build_sub_files +( + id INTEGER, + build_id INTEGER, + is_serialized_file INTEGER, + name TEXT, + size INTEGER, + PRIMARY KEY (id, build_id) +); \ No newline at end of file diff --git a/Analyzer/Resources/AddrBuilds.sql b/Analyzer/Resources/AddrBuilds.sql new file mode 100644 index 0000000..c2fb981 --- /dev/null +++ b/Analyzer/Resources/AddrBuilds.sql @@ -0,0 +1,16 @@ +CREATE TABLE IF NOT EXISTS addr_builds +( + id INTEGER, + name TEXT, + build_target INTEGER, + start_time TEXT, + duration REAL, + error TEXT, + package_version TEXT, + player_version TEXT, + build_script TEXT, + result_hash TEXT, + type INTEGER, + unity_version TEXT, + PRIMARY KEY (id) +); diff --git a/Analyzer/Resources/AnimationClip.sql b/Analyzer/Resources/AnimationClip.sql index 375cb66..3637968 100644 --- a/Analyzer/Resources/AnimationClip.sql +++ b/Analyzer/Resources/AnimationClip.sql @@ -1,4 +1,4 @@ -CREATE TABLE animation_clips( +CREATE TABLE IF NOT EXISTS animation_clips( id INTEGER, legacy INTEGER, events INTEGER, diff --git a/Analyzer/Resources/AssetBundle.sql b/Analyzer/Resources/AssetBundle.sql index 24b2f55..26aed13 100644 --- a/Analyzer/Resources/AssetBundle.sql +++ b/Analyzer/Resources/AssetBundle.sql @@ -1,9 +1,9 @@ -CREATE TABLE assets( +CREATE TABLE IF NOT EXISTS assets( object INTEGER, name TEXT ); -CREATE TABLE asset_dependencies( +CREATE TABLE IF NOT EXISTS asset_dependencies( object INTEGER, dependency INTEGER ); diff --git a/Analyzer/Resources/AudioClip.sql b/Analyzer/Resources/AudioClip.sql index bc80b4b..998085a 100644 --- a/Analyzer/Resources/AudioClip.sql +++ b/Analyzer/Resources/AudioClip.sql @@ -1,16 +1,16 @@ -CREATE TABLE audio_load_types( +CREATE TABLE IF NOT EXISTS audio_load_types( id INTEGER, name TEXT, PRIMARY KEY (id) ); -CREATE TABLE audio_formats( +CREATE TABLE IF NOT EXISTS audio_formats( id INTEGER, name TEXT, PRIMARY KEY (id) ); -CREATE TABLE audio_clips( +CREATE TABLE IF NOT EXISTS audio_clips( id INTEGER, bits_per_sample INTEGER, frequency INTEGER, diff --git a/Analyzer/Resources/Init.sql b/Analyzer/Resources/Init.sql index a41a44a..6f384b5 100644 --- a/Analyzer/Resources/Init.sql +++ b/Analyzer/Resources/Init.sql @@ -1,11 +1,11 @@ -CREATE TABLE types +CREATE TABLE IF NOT EXISTS types ( id INTEGER, name TEXT, PRIMARY KEY (id) ); -CREATE TABLE asset_bundles +CREATE TABLE IF NOT EXISTS asset_bundles ( id INTEGER, name TEXT, @@ -13,7 +13,7 @@ CREATE TABLE asset_bundles PRIMARY KEY (id) ); -CREATE TABLE serialized_files +CREATE TABLE IF NOT EXISTS serialized_files ( id INTEGER, asset_bundle INTEGER, @@ -21,7 +21,7 @@ CREATE TABLE serialized_files PRIMARY KEY (id) ); -CREATE TABLE objects +CREATE TABLE IF NOT EXISTS objects ( id INTEGER, object_id INTEGER, @@ -34,7 +34,7 @@ CREATE TABLE objects PRIMARY KEY (id) ); -CREATE TABLE refs +CREATE TABLE IF NOT EXISTS refs ( object INTEGER, referenced_object INTEGER, diff --git a/Analyzer/Resources/Mesh.sql b/Analyzer/Resources/Mesh.sql index c1d5ea2..16a1566 100644 --- a/Analyzer/Resources/Mesh.sql +++ b/Analyzer/Resources/Mesh.sql @@ -1,4 +1,4 @@ -CREATE TABLE meshes( +CREATE TABLE IF NOT EXISTS meshes( id INTEGER, sub_meshes INTEGER, blend_shapes INTEGER, diff --git a/Analyzer/Resources/Shader.sql b/Analyzer/Resources/Shader.sql index 2b05f96..d633744 100644 --- a/Analyzer/Resources/Shader.sql +++ b/Analyzer/Resources/Shader.sql @@ -1,28 +1,28 @@ -CREATE TABLE shaders( +CREATE TABLE IF NOT EXISTS shaders( id INTEGER, decompressed_size INTEGER, unique_programs INTEGER, PRIMARY KEY (id) ); -CREATE TABLE shader_keywords( +CREATE TABLE IF NOT EXISTS shader_keywords( id INTEGER, keyword TEXT, PRIMARY KEY (id) ); -CREATE TABLE shader_subprogram_keywords( +CREATE TABLE IF NOT EXISTS shader_subprogram_keywords( subprogram_id INTEGER, keyword_id INTEGER ); -CREATE TABLE shader_apis( +CREATE TABLE IF NOT EXISTS shader_apis( id INTEGER, name TEXT, PRIMARY KEY (id) ); -CREATE TABLE shader_subprograms( +CREATE TABLE IF NOT EXISTS shader_subprograms( id INTEGER, shader INTEGER, sub_shader INTEGER, diff --git a/Analyzer/Resources/Texture2D.sql b/Analyzer/Resources/Texture2D.sql index 5a9ba02..80ea8ea 100644 --- a/Analyzer/Resources/Texture2D.sql +++ b/Analyzer/Resources/Texture2D.sql @@ -1,11 +1,11 @@ -CREATE TABLE texture_formats +CREATE TABLE IF NOT EXISTS texture_formats ( id INTEGER, name TEXT, PRIMARY KEY (id) ); -CREATE TABLE textures +CREATE TABLE IF NOT EXISTS textures ( id INTEGER, width INTEGER, diff --git a/Analyzer/SQLite/Commands/AbstractCommand.cs b/Analyzer/SQLite/Commands/AbstractCommand.cs new file mode 100644 index 0000000..36e55f6 --- /dev/null +++ b/Analyzer/SQLite/Commands/AbstractCommand.cs @@ -0,0 +1,74 @@ +using Microsoft.Data.Sqlite; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Analyzer.SQLite.Commands +{ + internal abstract class AbstractCommand + { + protected abstract string TableName { get; } + protected abstract Dictionary Fields { get; } + + private SqliteCommand m_Command = new SqliteCommand(); + + protected virtual string DDLSource { get => null; } + + // run data definition language commands to create + // tables and views, run once at the beginning of creating + // the database + public void RunDDL(SqliteConnection database) + { + if (DDLSource == null) + return; + using var command = database.CreateCommand(); + command.CommandText = DDLSource; + command.ExecuteNonQuery(); + } + + public void CreateCommand(SqliteConnection database) + { + RunDDL(database); + + m_Command = database.CreateCommand(); + var commandText = new StringBuilder($"INSERT INTO {TableName} ("); + commandText.Append(string.Join(", ", Fields.Keys)); + commandText.Append(") VALUES (@"); + commandText.Append(string.Join(", @", Fields.Keys)); + commandText.Append(")"); + m_Command.CommandText = commandText.ToString(); + + foreach (var entry in Fields) + { + m_Command.Parameters.Add("@" + entry.Key, entry.Value); + } + } + public void SetValue(string key, object value) + { + string prefixedKey = $"@{key}"; + if (m_Command.Parameters.Contains(prefixedKey)) + { + m_Command.Parameters[prefixedKey].Value = value ?? DBNull.Value; + } + else + { + throw new ArgumentException($"Parameter '{key}' does not exist in the command."); + } + } + + public void SetTransaction(SqliteTransaction transaction) + { + m_Command.Transaction = transaction; + } + + public int ExecuteNonQuery() + { + return m_Command.ExecuteNonQuery(); + } + + public void Dispose() + { + m_Command?.Dispose(); + } + } +} diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuild.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuild.cs new file mode 100644 index 0000000..081e42f --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuild.cs @@ -0,0 +1,32 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + internal class AddressablesBuild : AbstractCommand + { + protected override string TableName { get => "addr_builds"; } + + protected override string DDLSource => Properties.Resources.AddrBuilds; + protected override Dictionary Fields { get => new Dictionary + { + { "name", SqliteType.Text }, + { "build_target", SqliteType.Integer }, + { "start_time", SqliteType.Integer }, + { "duration", SqliteType.Real }, + { "error", SqliteType.Text }, + { "package_version", SqliteType.Text }, + { "player_version", SqliteType.Text }, + { "build_script", SqliteType.Text }, + { "result_hash", SqliteType.Text }, + { "type", SqliteType.Integer }, + { "unity_version", SqliteType.Text } + }; } + public AddressablesBuild() + { + + } + + + } +} diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundle.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundle.cs new file mode 100644 index 0000000..7d51fd9 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundle.cs @@ -0,0 +1,58 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_bundles + ( + id INTEGER, + build_id INTEGER, + asset_count INTEGER, + build_status INTEGER, + crc INTEGER, + compression TEXT, + dependency_file_size INTEGER, + expanded_dependency_file_size INTEGER, + file_size INTEGER, + group_rid INTEGER, + hash TEXT, + internal_name TEXT, + load_path TEXT, + name TEXT, + provider TEXT, + result_type TEXT, + PRIMARY KEY (id, build_id) + ); + */ + internal class AddressablesBuildBundle : AbstractCommand + { + protected override string TableName => "addr_build_bundles"; + + protected override string DDLSource => Properties.Resources.AddrBuildBundles; + + protected override Dictionary Fields => new Dictionary + { + { "id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "asset_count", SqliteType.Integer }, + { "build_status", SqliteType.Integer }, + { "crc", SqliteType.Integer }, + { "compression", SqliteType.Text }, + { "dependency_file_size", SqliteType.Integer }, + { "expanded_dependency_file_size", SqliteType.Integer }, + { "file_size", SqliteType.Integer }, + { "group_rid", SqliteType.Integer }, + { "hash", SqliteType.Text }, // JSON object stored as TEXT + { "internal_name", SqliteType.Text }, + { "load_path", SqliteType.Text }, + { "name", SqliteType.Text }, + { "provider", SqliteType.Text }, + { "result_type", SqliteType.Text } + }; + + public AddressablesBuildBundle() + { + } + } +} diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundleDependency.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundleDependency.cs new file mode 100644 index 0000000..95fcb5e --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundleDependency.cs @@ -0,0 +1,33 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_bundle_dependencies + ( + bundle_id INTEGER, + build_id INTEGER, + dependency_rid INTEGER, + PRIMARY KEY (bundle_id, build_id, dependency_rid), + FOREIGN KEY (bundle_id, build_id) REFERENCES addr_build_bundles(id, build_id) + ); + */ + internal class AddressablesBuildBundleDependency : AbstractCommand + { + protected override string TableName => "addr_build_bundle_dependencies"; + + protected override string DDLSource => Properties.Resources.AddrBuildBundleDependencies; + + protected override Dictionary Fields => new Dictionary + { + { "bundle_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "dependency_rid", SqliteType.Integer } + }; + + public AddressablesBuildBundleDependency() + { + } + } +} diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundleDependentBundle.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundleDependentBundle.cs new file mode 100644 index 0000000..0956889 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundleDependentBundle.cs @@ -0,0 +1,34 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_bundle_dependent_bundles + ( + bundle_id INTEGER, + build_id INTEGER, + dependent_bundle_rid INTEGER, + PRIMARY KEY (bundle_id, build_id, dependent_bundle_rid), + FOREIGN KEY (bundle_id, build_id) REFERENCES addr_build_bundles(id, build_id) + ); + */ + internal class AddressablesBuildBundleDependentBundle : AbstractCommand + { + protected override string TableName => "addr_build_bundle_dependent_bundles"; + + protected override string DDLSource => Properties.Resources.AddrBuildBundleDependentBundles; + + protected override Dictionary Fields => new Dictionary + { + { "bundle_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "dependent_bundle_rid", SqliteType.Integer } + }; + + public AddressablesBuildBundleDependentBundle() + { + } + } +} + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundleExpandedDependency.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundleExpandedDependency.cs new file mode 100644 index 0000000..d978862 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundleExpandedDependency.cs @@ -0,0 +1,32 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_bundle_expanded_dependencies + ( + bundle_id INTEGER, + build_id INTEGER, + dependency_rid INTEGER, + PRIMARY KEY (bundle_id, build_id, dependency_rid), + FOREIGN KEY (bundle_id, build_id) REFERENCES addr_build_bundles(id, build_id) + ); + */ + internal class AddressablesBuildBundleExpandedDependency : AbstractCommand + { + protected override string TableName => "addr_build_bundle_expanded_dependencies"; + + protected override string DDLSource => Properties.Resources.AddrBuildBundleExpandedDependencies; + protected override Dictionary Fields => new Dictionary + { + { "bundle_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "dependency_rid", SqliteType.Integer } + }; + + public AddressablesBuildBundleExpandedDependency() + { + } + } +} diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundleFile.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundleFile.cs new file mode 100644 index 0000000..2cd1282 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundleFile.cs @@ -0,0 +1,34 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_bundle_files + ( + bundle_id INTEGER, + build_id INTEGER, + file_rid INTEGER, + PRIMARY KEY (bundle_id, build_id, file_rid), + FOREIGN KEY (bundle_id, build_id) REFERENCES addr_build_bundles(id, build_id) + ); + */ + internal class AddressablesBuildBundleFile : AbstractCommand + { + protected override string TableName => "addr_build_bundle_files"; + + protected override string DDLSource => Properties.Resources.AddrBuildBundleFiles; + + protected override Dictionary Fields => new Dictionary + { + { "bundle_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "file_rid", SqliteType.Integer } + }; + + public AddressablesBuildBundleFile() + { + } + } +} + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundleRegularDependency.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundleRegularDependency.cs new file mode 100644 index 0000000..5063c5c --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildBundleRegularDependency.cs @@ -0,0 +1,34 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_bundle_regular_dependencies + ( + bundle_id INTEGER, + build_id INTEGER, + dependency_rid INTEGER, + PRIMARY KEY (bundle_id, build_id, dependency_rid), + FOREIGN KEY (bundle_id, build_id) REFERENCES addr_build_bundles(id, build_id) + ); + */ + internal class AddressablesBuildBundleRegularDependency : AbstractCommand + { + protected override string TableName => "addr_build_bundle_regular_dependencies"; + + protected override string DDLSource => Properties.Resources.AddrBuildBundleRegularDependencies; + + protected override Dictionary Fields => new Dictionary + { + { "bundle_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "dependency_rid", SqliteType.Integer } + }; + + public AddressablesBuildBundleRegularDependency() + { + } + } +} + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildDataFromOtherAsset.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildDataFromOtherAsset.cs new file mode 100644 index 0000000..2cfe93f --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildDataFromOtherAsset.cs @@ -0,0 +1,44 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_data_from_other_assets + ( + id INTEGER, + build_id INTEGER, + asset_guid TEXT, + asset_path TEXT, + file INTEGER, + main_asset_type INTEGER, + object_count INTEGER, + serialized_size INTEGER, + streamed_size INTEGER, + PRIMARY KEY (id, build_id) + ); + */ + internal class AddressablesBuildDataFromOtherAsset : AbstractCommand + { + protected override string TableName => "addr_build_data_from_other_assets"; + + protected override string DDLSource => Properties.Resources.AddrBuildDataFromOtherAssets; + + protected override Dictionary Fields => new Dictionary + { + { "id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "asset_guid", SqliteType.Text }, + { "asset_path", SqliteType.Text }, + { "file", SqliteType.Integer }, + { "main_asset_type", SqliteType.Integer }, + { "object_count", SqliteType.Integer }, + { "serialized_size", SqliteType.Integer }, + { "streamed_size", SqliteType.Integer } + }; + + public AddressablesBuildDataFromOtherAsset() + { + } + } +} diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildDataFromOtherAssetObject.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildDataFromOtherAssetObject.cs new file mode 100644 index 0000000..c53f985 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildDataFromOtherAssetObject.cs @@ -0,0 +1,44 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_data_from_other_asset_objects + ( + data_from_other_asset_id INTEGER, + build_id INTEGER, + asset_type INTEGER, + component_name TEXT, + local_identifier_in_file INTEGER, + object_name TEXT, + serialized_size INTEGER, + streamed_size INTEGER, + PRIMARY KEY (data_from_other_asset_id, build_id, local_identifier_in_file), + FOREIGN KEY (data_from_other_asset_id, build_id) REFERENCES addr_build_data_from_other_assets(id, build_id) + ); + */ + internal class AddressablesBuildDataFromOtherAssetObject : AbstractCommand + { + protected override string TableName => "addr_build_data_from_other_asset_objects"; + + protected override string DDLSource => Properties.Resources.AddrBuildDataFromOtherAssetObjects; + + protected override Dictionary Fields => new Dictionary + { + { "data_from_other_asset_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "asset_type", SqliteType.Integer }, + { "component_name", SqliteType.Text }, + { "local_identifier_in_file", SqliteType.Integer }, + { "object_name", SqliteType.Text }, + { "serialized_size", SqliteType.Integer }, + { "streamed_size", SqliteType.Integer } + }; + + public AddressablesBuildDataFromOtherAssetObject() + { + } + } +} + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildDataFromOtherAssetObjectReference.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildDataFromOtherAssetObjectReference.cs new file mode 100644 index 0000000..7f49b64 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildDataFromOtherAssetObjectReference.cs @@ -0,0 +1,36 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_data_from_other_asset_object_references + ( + data_from_other_asset_id INTEGER, + build_id INTEGER, + local_identifier_in_file INTEGER, + asset_id INTEGER, + object_id INTEGER, + PRIMARY KEY (data_from_other_asset_id, build_id, local_identifier_in_file, asset_id, object_id), + FOREIGN KEY (data_from_other_asset_id, build_id, local_identifier_in_file) REFERENCES addr_build_data_from_other_asset_objects(data_from_other_asset_id, build_id, local_identifier_in_file) + ); + */ + internal class AddressablesBuildDataFromOtherAssetObjectReference : AbstractCommand + { + protected override string TableName => "addr_build_data_from_other_asset_object_references"; + + protected override string DDLSource => Properties.Resources.AddrBuildDataFromOtherAssetObjectReferences; + protected override Dictionary Fields => new Dictionary + { + { "data_from_other_asset_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "local_identifier_in_file", SqliteType.Integer }, + { "asset_id", SqliteType.Integer }, + { "object_id", SqliteType.Integer } + }; + + public AddressablesBuildDataFromOtherAssetObjectReference() + { + } + } +} diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildDataFromOtherAssetReferencingAsset.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildDataFromOtherAssetReferencingAsset.cs new file mode 100644 index 0000000..68895bb --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildDataFromOtherAssetReferencingAsset.cs @@ -0,0 +1,34 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_data_from_other_asset_referencing_assets + ( + data_from_other_asset_id INTEGER, + build_id INTEGER, + referencing_asset_rid INTEGER, + PRIMARY KEY (data_from_other_asset_id, build_id, referencing_asset_rid), + FOREIGN KEY (data_from_other_asset_id, build_id) REFERENCES addr_build_data_from_other_assets(id, build_id) + ); + */ + internal class AddressablesBuildDataFromOtherAssetReferencingAsset : AbstractCommand + { + protected override string TableName => "addr_build_data_from_other_asset_referencing_assets"; + + protected override string DDLSource => Properties.Resources.AddrBuildDataFromOtherAssetReferencingAssets; + + protected override Dictionary Fields => new Dictionary + { + { "data_from_other_asset_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "referencing_asset_rid", SqliteType.Integer } + }; + + public AddressablesBuildDataFromOtherAssetReferencingAsset() + { + } + } +} + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildExplicitAsset.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildExplicitAsset.cs new file mode 100644 index 0000000..080bdee --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildExplicitAsset.cs @@ -0,0 +1,51 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_explicit_assets + ( + id INTEGER, + build_id INTEGER, + bundle INTEGER, + file INTEGER, + asset_hash TEXT, + asset_path TEXT, + addressable_name TEXT, + group_guid TEXT, + guid TEXT, + internal_id TEXT, + main_asset_type INTEGER, + serialized_size INTEGER, + streamed_size INTEGER, + PRIMARY KEY (id, build_id) + ); + */ + internal class AddressablesBuildExplicitAsset : AbstractCommand + { + protected override string TableName => "addr_build_explicit_assets"; + + protected override string DDLSource => Properties.Resources.AddrBuildExplicitAssets; + + protected override Dictionary Fields => new Dictionary + { + { "id", SqliteType.Integer }, + { "build_id", SqliteType.Integer}, + { "bundle", SqliteType.Integer}, + { "file", SqliteType.Integer }, + { "asset_hash", SqliteType.Text }, + { "asset_path", SqliteType.Text }, + { "addressable_name", SqliteType.Text }, + { "group_guid", SqliteType.Text }, + { "guid", SqliteType.Text }, + { "internal_id", SqliteType.Text }, + { "main_asset_type", SqliteType.Integer }, + { "streamed_size", SqliteType.Integer }, + { "serialized_size", SqliteType.Integer } + }; + public AddressablesBuildExplicitAsset() + { + } + } +} diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildExplicitAssetExternallyReferencedAsset.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildExplicitAssetExternallyReferencedAsset.cs new file mode 100644 index 0000000..bb23568 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildExplicitAssetExternallyReferencedAsset.cs @@ -0,0 +1,34 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_explicit_asset_externally_referenced_assets + ( + explicit_asset_id INTEGER, + build_id INTEGER, + externally_referenced_asset_rid INTEGER, + PRIMARY KEY (explicit_asset_id, build_id, externally_referenced_asset_rid), + FOREIGN KEY (explicit_asset_id, build_id) REFERENCES addr_build_explicit_assets(id, build_id) + ); + */ + internal class AddressablesBuildExplicitAssetExternallyReferencedAsset : AbstractCommand + { + protected override string TableName => "addr_build_explicit_asset_externally_referenced_assets"; + + protected override string DDLSource => Properties.Resources.AddrBuildExplicitAssetExternallyReferencedAssets; + + protected override Dictionary Fields => new Dictionary + { + { "explicit_asset_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "externally_referenced_asset_rid", SqliteType.Integer } + }; + + public AddressablesBuildExplicitAssetExternallyReferencedAsset() + { + } + } +} + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildExplicitAssetInternalReferencedExplicitAsset.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildExplicitAssetInternalReferencedExplicitAsset.cs new file mode 100644 index 0000000..13bf6cf --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildExplicitAssetInternalReferencedExplicitAsset.cs @@ -0,0 +1,34 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_explicit_asset_internal_referenced_explicit_assets + ( + explicit_asset_id INTEGER, + build_id INTEGER, + internal_referenced_explicit_asset_rid INTEGER, + PRIMARY KEY (explicit_asset_id, build_id, internal_referenced_explicit_asset_rid), + FOREIGN KEY (explicit_asset_id, build_id) REFERENCES addr_build_explicit_assets(id, build_id) + ); + */ + internal class AddressablesBuildExplicitAssetInternalReferencedExplicitAsset : AbstractCommand + { + protected override string TableName => "addr_build_explicit_asset_internal_referenced_explicit_assets"; + + protected override string DDLSource => Properties.Resources.AddrBuildExplicitAssetInternalReferencedExplicitAssets; + + protected override Dictionary Fields => new Dictionary + { + { "explicit_asset_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "internal_referenced_explicit_asset_rid", SqliteType.Integer } + }; + + public AddressablesBuildExplicitAssetInternalReferencedExplicitAsset() + { + } + } +} + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildExplicitAssetInternalReferencedOtherAsset.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildExplicitAssetInternalReferencedOtherAsset.cs new file mode 100644 index 0000000..98b5db8 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildExplicitAssetInternalReferencedOtherAsset.cs @@ -0,0 +1,34 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_explicit_asset_internal_referenced_other_assets + ( + explicit_asset_id INTEGER, + build_id INTEGER, + internal_referenced_other_asset_rid INTEGER, + PRIMARY KEY (explicit_asset_id, build_id, internal_referenced_other_asset_rid), + FOREIGN KEY (explicit_asset_id, build_id) REFERENCES addr_build_explicit_assets(id, build_id) + ); + */ + internal class AddressablesBuildExplicitAssetInternalReferencedOtherAsset : AbstractCommand + { + protected override string TableName => "addr_build_explicit_asset_internal_referenced_other_assets"; + + protected override string DDLSource => Properties.Resources.AddrBuildExplicitAssetInternalReferencedOtherAssets; + + protected override Dictionary Fields => new Dictionary + { + { "explicit_asset_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "internal_referenced_other_asset_rid", SqliteType.Integer } + }; + + public AddressablesBuildExplicitAssetInternalReferencedOtherAsset() + { + } + } +} + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildExplicitAssetLabel.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildExplicitAssetLabel.cs new file mode 100644 index 0000000..fcb2d34 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildExplicitAssetLabel.cs @@ -0,0 +1,34 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_explicit_asset_labels + ( + explicit_asset_id INTEGER, + build_id INTEGER, + label TEXT, + PRIMARY KEY (explicit_asset_id, build_id, label), + FOREIGN KEY (explicit_asset_id, build_id) REFERENCES addr_build_explicit_assets(id, build_id) + ); + */ + internal class AddressablesBuildExplicitAssetLabel : AbstractCommand + { + protected override string TableName => "addr_build_explicit_asset_labels"; + + protected override string DDLSource => Properties.Resources.AddrBuildExplicitAssetLabels; + + protected override Dictionary Fields => new Dictionary + { + { "explicit_asset_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "label", SqliteType.Text } + }; + + public AddressablesBuildExplicitAssetLabel() + { + } + } +} + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildFile.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildFile.cs new file mode 100644 index 0000000..9286565 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildFile.cs @@ -0,0 +1,44 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_files + ( + id INTEGER, + build_id INTEGER, + bundle INTEGER, + bundle_object_info_size INTEGER, + mono_script_count INTEGER, + mono_script_size INTEGER, + name TEXT, + preload_info_size INTEGER, + write_result_filename TEXT, + PRIMARY KEY (id, build_id) + ); + */ + internal class AddressablesBuildFile : AbstractCommand + { + protected override string TableName => "addr_build_files"; + + protected override string DDLSource => Properties.Resources.AddrBuildFiles; + + protected override Dictionary Fields => new Dictionary + { + { "id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "bundle", SqliteType.Integer }, + { "bundle_object_info_size", SqliteType.Integer }, + { "mono_script_count", SqliteType.Integer }, + { "mono_script_size", SqliteType.Integer }, + { "name", SqliteType.Text }, + { "preload_info_size", SqliteType.Integer }, + { "write_result_filename", SqliteType.Text } + }; + + public AddressablesBuildFile() + { + } + } +} diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildFileAsset.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildFileAsset.cs new file mode 100644 index 0000000..d6ff976 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildFileAsset.cs @@ -0,0 +1,35 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_file_assets + ( + file_id INTEGER, + build_id INTEGER, + asset_rid INTEGER, + PRIMARY KEY (file_id, build_id, asset_rid), + FOREIGN KEY (file_id, build_id) REFERENCES addr_build_files(id, build_id) + ); + */ + internal class AddressablesBuildFileAsset : AbstractCommand + { + protected override string TableName => "addr_build_file_assets"; + + protected override string DDLSource => Properties.Resources.AddrBuildFileAssets; + + protected override Dictionary Fields => new Dictionary + { + { "file_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "asset_rid", SqliteType.Integer } + }; + + public AddressablesBuildFileAsset() + { + } + } +} + + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildFileExternalReference.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildFileExternalReference.cs new file mode 100644 index 0000000..87de495 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildFileExternalReference.cs @@ -0,0 +1,35 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_file_external_references + ( + file_id INTEGER, + build_id INTEGER, + external_reference_rid INTEGER, + PRIMARY KEY (file_id, build_id, external_reference_rid), + FOREIGN KEY (file_id, build_id) REFERENCES addr_build_files(id, build_id) + ); + */ + internal class AddressablesBuildFileExternalReference : AbstractCommand + { + protected override string TableName => "addr_build_file_external_references"; + + protected override string DDLSource => Properties.Resources.AddrBuildFileExternalReferences; + + protected override Dictionary Fields => new Dictionary + { + { "file_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "external_reference_rid", SqliteType.Integer } + }; + + public AddressablesBuildFileExternalReference() + { + } + } +} + + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildFileOtherAsset.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildFileOtherAsset.cs new file mode 100644 index 0000000..a989f27 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildFileOtherAsset.cs @@ -0,0 +1,35 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_file_other_assets + ( + file_id INTEGER, + build_id INTEGER, + other_asset_rid INTEGER, + PRIMARY KEY (file_id, build_id, other_asset_rid), + FOREIGN KEY (file_id, build_id) REFERENCES addr_build_files(id, build_id) + ); + */ + internal class AddressablesBuildFileOtherAsset : AbstractCommand + { + protected override string TableName => "addr_build_file_other_assets"; + + protected override string DDLSource => Properties.Resources.AddrBuildFileOtherAssets; + + protected override Dictionary Fields => new Dictionary + { + { "file_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "other_asset_rid", SqliteType.Integer } + }; + + public AddressablesBuildFileOtherAsset() + { + } + } +} + + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildFileSubFile.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildFileSubFile.cs new file mode 100644 index 0000000..264e46f --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildFileSubFile.cs @@ -0,0 +1,35 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_file_sub_files + ( + file_id INTEGER, + build_id INTEGER, + sub_file_rid INTEGER, + PRIMARY KEY (file_id, build_id, sub_file_rid), + FOREIGN KEY (file_id, build_id) REFERENCES addr_build_files(id, build_id) + ); + */ + internal class AddressablesBuildFileSubFile : AbstractCommand + { + protected override string TableName => "addr_build_file_sub_files"; + + protected override string DDLSource => Properties.Resources.AddrBuildFileSubFiles; + + protected override Dictionary Fields => new Dictionary + { + { "file_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "sub_file_rid", SqliteType.Integer } + }; + + public AddressablesBuildFileSubFile() + { + } + } +} + + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildGroup.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildGroup.cs new file mode 100644 index 0000000..97cbe6c --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildGroup.cs @@ -0,0 +1,37 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_groups + ( + id INTEGER, + build_id INTEGER, + guid TEXT, + name TEXT, + packing_mode TEXT, + PRIMARY KEY (id, build_id) + ); + */ + internal class AddressablesBuildGroup : AbstractCommand + { + protected override string TableName => "addr_build_groups"; + + protected override string DDLSource => Properties.Resources.AddrBuildGroups; + + protected override Dictionary Fields => new Dictionary + { + { "id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "guid", SqliteType.Text }, + { "name", SqliteType.Text }, + { "packing_mode", SqliteType.Text }, + }; + + public AddressablesBuildGroup() + { + } + } +} + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildGroupBundle.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildGroupBundle.cs new file mode 100644 index 0000000..9c5ec8b --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildGroupBundle.cs @@ -0,0 +1,36 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_group_bundles + ( + group_id INTEGER, + build_id INTEGER, + bundle_rid INTEGER, + PRIMARY KEY (group_id, build_id, bundle_rid), + FOREIGN KEY (group_id, build_id) REFERENCES addr_build_groups(id, build_id) + ); + */ + internal class AddressablesBuildGroupBundle : AbstractCommand + { + protected override string TableName => "addr_build_group_bundles"; + + protected override string DDLSource => Properties.Resources.AddrBuildGroupBundles; + + protected override Dictionary Fields => new Dictionary + { + { "group_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "bundle_rid", SqliteType.Integer } + }; + + public AddressablesBuildGroupBundle() + { + } + } +} + + + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildGroupSchema.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildGroupSchema.cs new file mode 100644 index 0000000..e7343d1 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildGroupSchema.cs @@ -0,0 +1,36 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_group_schemas + ( + group_id INTEGER, + build_id INTEGER, + schema_rid INTEGER, + PRIMARY KEY (group_id, build_id, schema_rid), + FOREIGN KEY (group_id, build_id) REFERENCES addr_build_groups(id, build_id) + ); + */ + internal class AddressablesBuildGroupSchema : AbstractCommand + { + protected override string TableName => "addr_build_group_schemas"; + + protected override string DDLSource => Properties.Resources.AddrBuildGroupSchemas; + + protected override Dictionary Fields => new Dictionary + { + { "group_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "schema_rid", SqliteType.Integer } + }; + + public AddressablesBuildGroupSchema() + { + } + } +} + + + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildSchema.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildSchema.cs new file mode 100644 index 0000000..4f80385 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildSchema.cs @@ -0,0 +1,35 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_schemas + ( + id INTEGER, + build_id INTEGER, + guid TEXT, + type TEXT, + PRIMARY KEY (id, build_id) + ); + */ + internal class AddressablesBuildSchema : AbstractCommand + { + protected override string TableName => "addr_build_schemas"; + + protected override string DDLSource => Properties.Resources.AddrBuildSchemas; + + protected override Dictionary Fields => new Dictionary + { + { "id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "guid", SqliteType.Text }, + { "type", SqliteType.Text } + }; + + public AddressablesBuildSchema() + { + } + } +} + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildSchemaDataPair.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildSchemaDataPair.cs new file mode 100644 index 0000000..8a259e7 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildSchemaDataPair.cs @@ -0,0 +1,39 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_schema_data_pairs + ( + schema_id INTEGER, + build_id INTEGER, + key TEXT, + value TEXT, + PRIMARY KEY (schema_id, build_id, key), + FOREIGN KEY (schema_id, build_id) REFERENCES addr_build_schemas(id, build_id) + ); + */ + internal class AddressablesBuildSchemaDataPair : AbstractCommand + { + protected override string TableName => "addr_build_schema_data_pairs"; + + protected override string DDLSource => Properties.Resources.AddrBuildSchemaDataPairs; + + protected override Dictionary Fields => new Dictionary + { + { "schema_id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "key", SqliteType.Text }, + { "value", SqliteType.Text } + }; + + public AddressablesBuildSchemaDataPair() + { + } + } +} + + + + diff --git a/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildSubFile.cs b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildSubFile.cs new file mode 100644 index 0000000..e25f477 --- /dev/null +++ b/Analyzer/SQLite/Commands/AddressablesBuildReport/AddressablesBuildSubFile.cs @@ -0,0 +1,36 @@ +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace Analyzer.SQLite.Commands.AddressablesBuildReport +{ + /* TABLE DEFINITION: + create table addr_build_sub_files + ( + id INTEGER, + build_id INTEGER, + is_serialized_file INTEGER, + name TEXT, + size INTEGER, + PRIMARY KEY (id, build_id) + ); + */ + internal class AddressablesBuildSubFile : AbstractCommand + { + protected override string TableName => "addr_build_sub_files"; + + protected override string DDLSource => Properties.Resources.AddrBuildSubFiles; + + protected override Dictionary Fields => new Dictionary + { + { "id", SqliteType.Integer }, + { "build_id", SqliteType.Integer }, + { "is_serialized_file", SqliteType.Integer }, + { "name", SqliteType.Text }, + { "size", SqliteType.Integer } + }; + + public AddressablesBuildSubFile() + { + } + } +} diff --git a/Analyzer/SQLite/Commands/SerializedFile/AddAssetBundle.cs b/Analyzer/SQLite/Commands/SerializedFile/AddAssetBundle.cs new file mode 100644 index 0000000..6f30853 --- /dev/null +++ b/Analyzer/SQLite/Commands/SerializedFile/AddAssetBundle.cs @@ -0,0 +1,29 @@ +using Analyzer.SQLite.Commands; +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace UnityDataTools.Analyzer.SQLite.Commands.SerializedFile +{ + /* TABLE DEFINITION: + create table asset_bundles + ( + id INTEGER, + name TEXT, + file_size INTEGER, + PRIMARY KEY (id) + ); + */ + internal class AddAssetBundle : AbstractCommand + { + protected override string TableName => "asset_bundles"; + + protected override string DDLSource => null; + + protected override Dictionary Fields => new() + { + { "id", SqliteType.Integer }, + { "name", SqliteType.Text }, + { "file_size", SqliteType.Integer } + }; + } +} \ No newline at end of file diff --git a/Analyzer/SQLite/Commands/SerializedFile/AddAssetDependency.cs b/Analyzer/SQLite/Commands/SerializedFile/AddAssetDependency.cs new file mode 100644 index 0000000..f8bcc45 --- /dev/null +++ b/Analyzer/SQLite/Commands/SerializedFile/AddAssetDependency.cs @@ -0,0 +1,27 @@ +using Analyzer.SQLite.Commands; +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace UnityDataTools.Analyzer.SQLite.Commands.SerializedFile +{ + /* TABLE DEFINITION: + create table asset_dependencies + ( + object INTEGER, + dependency INTEGER, + PRIMARY KEY (object, dependency) + ); + */ + internal class AddAssetDependency : AbstractCommand + { + protected override string TableName => "asset_dependencies"; + + protected override string DDLSource => Resources.AssetBundle; + + protected override Dictionary Fields => new() + { + { "object", SqliteType.Integer }, + { "dependency", SqliteType.Integer } + }; + } +} \ No newline at end of file diff --git a/Analyzer/SQLite/Commands/SerializedFile/AddObject.cs b/Analyzer/SQLite/Commands/SerializedFile/AddObject.cs new file mode 100644 index 0000000..18a28a5 --- /dev/null +++ b/Analyzer/SQLite/Commands/SerializedFile/AddObject.cs @@ -0,0 +1,38 @@ +using Analyzer.SQLite.Commands; +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace UnityDataTools.Analyzer.SQLite.Commands.SerializedFile +{ + /* TABLE DEFINITION: + create table objects + ( + id INTEGER, + object_id INTEGER, + serialized_file INTEGER, + type INTEGER, + name TEXT, + game_object INTEGER, + size INTEGER, + crc32 INTEGER, + PRIMARY KEY (id) + ); + */ + internal class AddObject : AbstractCommand + { + protected override string TableName => "objects"; + + protected override string DDLSource => null; + protected override Dictionary Fields => new() + { + { "id", SqliteType.Integer }, + { "object_id", SqliteType.Integer }, + { "serialized_file", SqliteType.Integer }, + { "type", SqliteType.Integer }, + { "name", SqliteType.Text }, + { "game_object", SqliteType.Integer }, + { "size", SqliteType.Integer }, + { "crc32", SqliteType.Integer } + }; + } +} \ No newline at end of file diff --git a/Analyzer/SQLite/Commands/SerializedFile/AddReference.cs b/Analyzer/SQLite/Commands/SerializedFile/AddReference.cs new file mode 100644 index 0000000..4fa2c01 --- /dev/null +++ b/Analyzer/SQLite/Commands/SerializedFile/AddReference.cs @@ -0,0 +1,31 @@ +using Analyzer.SQLite.Commands; +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace UnityDataTools.Analyzer.SQLite.Commands.SerializedFile +{ + /* TABLE DEFINITION: + create table refs + ( + object INTEGER, + referenced_object INTEGER, + property_path TEXT, + property_type TEXT, + PRIMARY KEY (object, referenced_object, property_path) + ); + */ + internal class AddReference : AbstractCommand + { + protected override string TableName => "refs"; + + protected override string DDLSource => null; + + protected override Dictionary Fields => new() + { + { "object", SqliteType.Integer }, + { "referenced_object", SqliteType.Integer }, + { "property_path", SqliteType.Text }, + { "property_type", SqliteType.Text } + }; + } +} \ No newline at end of file diff --git a/Analyzer/SQLite/Commands/SerializedFile/AddSerializedFile.cs b/Analyzer/SQLite/Commands/SerializedFile/AddSerializedFile.cs new file mode 100644 index 0000000..c563ba0 --- /dev/null +++ b/Analyzer/SQLite/Commands/SerializedFile/AddSerializedFile.cs @@ -0,0 +1,29 @@ +using Analyzer.SQLite.Commands; +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace UnityDataTools.Analyzer.SQLite.Commands.SerializedFile +{ + /* TABLE DEFINITION: + create table serialized_files + ( + id INTEGER, + asset_bundle INTEGER, + name TEXT, + PRIMARY KEY (id) + ); + */ + internal class AddSerializedFile : AbstractCommand + { + protected override string TableName => "serialized_files"; + + protected override string DDLSource => null; + + protected override Dictionary Fields => new() + { + { "id", SqliteType.Integer }, + { "asset_bundle", SqliteType.Integer }, + { "name", SqliteType.Text } + }; + } +} \ No newline at end of file diff --git a/Analyzer/SQLite/Commands/SerializedFile/AddType.cs b/Analyzer/SQLite/Commands/SerializedFile/AddType.cs new file mode 100644 index 0000000..945c16d --- /dev/null +++ b/Analyzer/SQLite/Commands/SerializedFile/AddType.cs @@ -0,0 +1,27 @@ +using Analyzer.SQLite.Commands; +using Microsoft.Data.Sqlite; +using System.Collections.Generic; + +namespace UnityDataTools.Analyzer.SQLite.Commands.SerializedFile +{ + /* TABLE DEFINITION: + create table types + ( + id INTEGER, + name TEXT, + PRIMARY KEY (id) + ); + */ + internal class AddType : AbstractCommand + { + protected override string TableName => "types"; + + protected override string DDLSource => null; + + protected override Dictionary Fields => new() + { + { "id", SqliteType.Integer }, + { "name", SqliteType.Text } + }; + } +} \ No newline at end of file diff --git a/Analyzer/SQLite/Handlers/AnimationClipHandler.cs b/Analyzer/SQLite/Handlers/AnimationClipHandler.cs index d00c60f..6251fe8 100644 --- a/Analyzer/SQLite/Handlers/AnimationClipHandler.cs +++ b/Analyzer/SQLite/Handlers/AnimationClipHandler.cs @@ -3,6 +3,7 @@ using UnityDataTools.Analyzer.SerializedObjects; using UnityDataTools.FileSystem.TypeTreeReaders; + namespace UnityDataTools.Analyzer.SQLite.Handlers; public class AnimationClipHandler : ISQLiteHandler @@ -12,7 +13,7 @@ public class AnimationClipHandler : ISQLiteHandler public void Init(SqliteConnection db) { using var command = db.CreateCommand(); - command.CommandText = Properties.Resources.AnimationClip; + command.CommandText = Resources.AnimationClip; command.ExecuteNonQuery(); m_InsertCommand = db.CreateCommand(); diff --git a/Analyzer/SQLite/Handlers/AssetBundleHandler.cs b/Analyzer/SQLite/Handlers/AssetBundleHandler.cs deleted file mode 100644 index 80bbc6b..0000000 --- a/Analyzer/SQLite/Handlers/AssetBundleHandler.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.Text.RegularExpressions; -using Microsoft.Data.Sqlite; -using UnityDataTools.Analyzer.SerializedObjects; -using UnityDataTools.FileSystem.TypeTreeReaders; - -namespace UnityDataTools.Analyzer.SQLite.Handlers; - -public class AssetBundleHandler : ISQLiteHandler -{ - SqliteCommand m_InsertCommand; - private SqliteCommand m_InsertDepCommand; - private Regex m_SceneNameRegex = new Regex(@"([^//]+)\.unity"); - - public void Init(SqliteConnection db) - { - using var command = db.CreateCommand(); - command.CommandText = Properties.Resources.AssetBundle; - command.ExecuteNonQuery(); - - m_InsertCommand = db.CreateCommand(); - - m_InsertCommand.CommandText = "INSERT INTO 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.Parameters.Add("@object", SqliteType.Integer); - m_InsertDepCommand.Parameters.Add("@dependency", SqliteType.Integer); - } - - public void Process(Context ctx, long objectId, RandomAccessReader reader, out string name, out long streamDataSize) - { - var assetBundle = AssetBundle.Read(reader); - - foreach (var asset in assetBundle.Assets) - { - if (!assetBundle.IsSceneAssetBundle) - { - var fileId = ctx.LocalToDbFileId[asset.PPtr.FileId]; - var objId = ctx.ObjectIdProvider.GetId((fileId, asset.PPtr.PathId)); - m_InsertCommand.Transaction = ctx.Transaction; - m_InsertCommand.Parameters["@object"].Value = objId; - m_InsertCommand.Parameters["@name"].Value = asset.Name; - m_InsertCommand.ExecuteNonQuery(); - - for (int i = asset.PreloadIndex; i < asset.PreloadIndex + asset.PreloadSize; ++i) - { - var dependency = assetBundle.PreloadTable[i]; - var depFileId = ctx.LocalToDbFileId[dependency.FileId]; - var depId = ctx.ObjectIdProvider.GetId((depFileId, dependency.PathId)); - m_InsertDepCommand.Transaction = ctx.Transaction; - m_InsertDepCommand.Parameters["@object"].Value = objId; - m_InsertDepCommand.Parameters["@dependency"].Value = depId; - m_InsertDepCommand.ExecuteNonQuery(); - } - } - else - { - var match = m_SceneNameRegex.Match(asset.Name); - - if (match.Success) - { - var sceneName = match.Groups[1].Value; - var objId = ctx.ObjectIdProvider.GetId((ctx.SerializedFileIdProvider.GetId(sceneName), 0)); - m_InsertCommand.Transaction = ctx.Transaction; - m_InsertCommand.Parameters["@object"].Value = objId; - m_InsertCommand.Parameters["@name"].Value = asset.Name; - m_InsertCommand.ExecuteNonQuery(); - } - } - } - - name = assetBundle.Name; - streamDataSize = 0; - } - - 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.ExecuteNonQuery(); - - command.CommandText = "CREATE INDEX asset_dependencies_dependency ON asset_dependencies(dependency)"; - command.ExecuteNonQuery(); - } - - void IDisposable.Dispose() - { - m_InsertCommand?.Dispose(); - m_InsertDepCommand?.Dispose(); - } -} \ No newline at end of file diff --git a/Analyzer/SQLite/Handlers/AudioClipHandler.cs b/Analyzer/SQLite/Handlers/AudioClipHandler.cs index cfd542e..5d9af03 100644 --- a/Analyzer/SQLite/Handlers/AudioClipHandler.cs +++ b/Analyzer/SQLite/Handlers/AudioClipHandler.cs @@ -13,7 +13,7 @@ public class AudioClipHandler : ISQLiteHandler public void Init(SqliteConnection db) { using var command = db.CreateCommand(); - command.CommandText = Properties.Resources.AudioClip; + command.CommandText = Resources.AudioClip; command.ExecuteNonQuery(); m_InsertCommand = db.CreateCommand(); diff --git a/Analyzer/SQLite/Handlers/ISQLiteHandler.cs b/Analyzer/SQLite/Handlers/ISQLiteHandler.cs index ba6dfcf..66b0fea 100644 --- a/Analyzer/SQLite/Handlers/ISQLiteHandler.cs +++ b/Analyzer/SQLite/Handlers/ISQLiteHandler.cs @@ -20,5 +20,13 @@ public interface ISQLiteHandler : IDisposable { void Init(Microsoft.Data.Sqlite.SqliteConnection db); void Process(Context ctx, long objectId, RandomAccessReader reader, out string name, out long streamDataSize); - void Finalize(Microsoft.Data.Sqlite.SqliteConnection db); +} + +public interface ISQLiteFileParser : IDisposable +{ + void Init(SqliteConnection db); + bool CanParse(string filename); + void Parse(string filename); + public bool Verbose { get; set; } + public bool SkipReferences { get; set; } } \ No newline at end of file diff --git a/Analyzer/SQLite/Handlers/MeshHandler.cs b/Analyzer/SQLite/Handlers/MeshHandler.cs index 1845b7f..85bb39c 100644 --- a/Analyzer/SQLite/Handlers/MeshHandler.cs +++ b/Analyzer/SQLite/Handlers/MeshHandler.cs @@ -13,7 +13,7 @@ public class MeshHandler : ISQLiteHandler public void Init(SqliteConnection db) { using var command = db.CreateCommand(); - command.CommandText = Properties.Resources.Mesh; + command.CommandText = Resources.Mesh; command.ExecuteNonQuery(); m_InsertCommand = db.CreateCommand(); diff --git a/Analyzer/SQLite/Handlers/ShaderHandler.cs b/Analyzer/SQLite/Handlers/ShaderHandler.cs index 6731aad..dd2602b 100644 --- a/Analyzer/SQLite/Handlers/ShaderHandler.cs +++ b/Analyzer/SQLite/Handlers/ShaderHandler.cs @@ -21,7 +21,7 @@ public void Init(SqliteConnection db) s_GlobalKeywords.Clear(); using var command = db.CreateCommand(); - command.CommandText = Properties.Resources.Shader; + command.CommandText = Resources.Shader; command.ExecuteNonQuery(); m_InsertCommand = db.CreateCommand(); diff --git a/Analyzer/SQLite/Handlers/Texture2DHandler.cs b/Analyzer/SQLite/Handlers/Texture2DHandler.cs index fe26f1a..0fc9499 100644 --- a/Analyzer/SQLite/Handlers/Texture2DHandler.cs +++ b/Analyzer/SQLite/Handlers/Texture2DHandler.cs @@ -12,7 +12,7 @@ public class Texture2DHandler : ISQLiteHandler public void Init(SqliteConnection db) { using var command = db.CreateCommand(); - command.CommandText = Properties.Resources.Texture2D; + command.CommandText = Resources.Texture2D; command.ExecuteNonQuery(); m_InsertCommand = db.CreateCommand(); diff --git a/Analyzer/SQLite/Parsers/AddressablesBuildLayoutParser.cs b/Analyzer/SQLite/Parsers/AddressablesBuildLayoutParser.cs new file mode 100644 index 0000000..a56155e --- /dev/null +++ b/Analyzer/SQLite/Parsers/AddressablesBuildLayoutParser.cs @@ -0,0 +1,90 @@ +using Analyzer.SQLite.Commands.AddressablesBuildReport; +using Analyzer.SQLite.Writers; +using Microsoft.Data.Sqlite; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityDataTools.Analyzer; +using UnityDataTools.Analyzer.Build; +using UnityDataTools.Analyzer.SQLite.Handlers; + +namespace Analyzer.SQLite.Parsers +{ + public class AddressablesBuildLayoutParser : ISQLiteFileParser + { + private AddressablesBuildLayoutSQLWriter m_Writer; + + public bool Verbose { get; set; } + public bool SkipReferences { get; set; } + + public void Dispose() + { + m_Writer.Dispose(); + } + public void Init(SqliteConnection db) + { + m_Writer = new AddressablesBuildLayoutSQLWriter(db); + m_Writer.Init(); + } + + public bool CanParse(string filename) + { + + if (Path.GetExtension(filename) != ".json") + return false; + + // Read the first line of the JSON file and check if it contains BuildResultHash + string firstLine = ""; + try + { + using (StreamReader reader = new StreamReader(filename)) + { + firstLine = reader.ReadLine(); + if (firstLine != null) + { + // Remove trailing comma if present and add closing brace to make it valid JSON + if (firstLine.TrimEnd().EndsWith(",")) + { + firstLine = firstLine.TrimEnd().TrimEnd(',') + "}"; + } + + using (JsonTextReader jsonReader = new JsonTextReader(new StringReader(firstLine))) + { + JsonSerializer serializer = new JsonSerializer(); + var jsonObject = serializer.Deserialize(jsonReader); + + // If the file has BuildResultHash, process it as an Addressables build + if (jsonObject != null && jsonObject["BuildResultHash"] != null) + { + return true; + } + } + } + } + } + catch (Exception e) + { + if (Verbose) + { + Console.Error.WriteLine($"Error reading JSON file {filename}: {e.Message}"); + } + } + return false; + } + + public void Parse(string filename) + { + using (StreamReader reader = File.OpenText(filename)) + { + JsonSerializer serializer = new JsonSerializer(); + BuildLayout buildLayout = (BuildLayout)serializer.Deserialize(reader, typeof(BuildLayout)); + m_Writer.WriteAddressablesBuild(filename, buildLayout); + } + } + } +} diff --git a/Analyzer/SQLite/Parsers/SerializedFileParser.cs b/Analyzer/SQLite/Parsers/SerializedFileParser.cs new file mode 100644 index 0000000..ef5bd31 --- /dev/null +++ b/Analyzer/SQLite/Parsers/SerializedFileParser.cs @@ -0,0 +1,185 @@ +using Analyzer.SQLite.Writers; +using Microsoft.Data.Sqlite; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityDataTools.Analyzer.SQLite.Handlers; +using UnityDataTools.FileSystem; + +namespace Analyzer.SQLite.Parsers +{ + public class SerializedFileParser : ISQLiteFileParser + { + private AssetBundleSQLiteWriter m_Writer; + + public bool Verbose { get; set; } + public bool SkipReferences { get; set; } + + public bool CanParse(string filename) + { + return ShouldIgnoreFile(filename) == false; + } + + + public void Dispose() + { + m_Writer.Dispose(); + } + + public void Init(SqliteConnection db) + { + m_Writer = new AssetBundleSQLiteWriter(db, SkipReferences); + m_Writer.Init(); + } + + public void Parse(string filename) + { + ProcessFile(filename, Path.GetDirectoryName(filename)); + } + + 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 IgnoredFileNames = new() + { + ".DS_Store", "boot.config", "archive_dependencies.bin", "scene_info.bin", "app.info", "link.xml", + "catalog.bin", "catalog.hash" + }; + + private static readonly HashSet IgnoredExtensions = new() + { + ".txt", ".resS", ".resource", ".json", ".dll", ".pdb", ".exe", ".manifest", ".entities", ".entityheader", + ".ini", ".config" + }; + + bool ProcessFile(string file, string rootDirectory) + { + 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); + + m_Writer.BeginAssetBundle(assetBundleName, new FileInfo(file).Length); + + foreach (var node in archive.Nodes) + { + if (node.Flags.HasFlag(ArchiveNodeFlags.SerializedFile)) + { + try + { + m_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. + 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 + { + m_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); + m_Writer.WriteSerializedFile(relativePath, file, Path.GetDirectoryName(file)); + } + } + catch (NotSupportedException) + { + Console.Error.WriteLine(); + //A "failed to load" error will already be logged by the UnityFileSystem library + + successful = false; + } + catch (Exception e) + { + Console.Error.WriteLine(); + Console.Error.WriteLine($"Error processing file: {file}"); + Console.WriteLine($"{e.GetType()}: {e.Message}"); + if (Verbose) + Console.WriteLine(e.StackTrace); + + successful = false; + } + + return successful; + } + + private static bool IsUnityArchive(string filePath) + { + // 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; + } + } + } +} diff --git a/Analyzer/SQLite/SQLiteWriter.cs b/Analyzer/SQLite/SQLiteWriter.cs deleted file mode 100644 index a463f3e..0000000 --- a/Analyzer/SQLite/SQLiteWriter.cs +++ /dev/null @@ -1,355 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Data.Sqlite; -using System.IO; -using System.Text.RegularExpressions; -using UnityDataTools.Analyzer.SQLite.Handlers; -using UnityDataTools.FileSystem; -using UnityDataTools.FileSystem.TypeTreeReaders; - -namespace UnityDataTools.Analyzer.SQLite; - -public class SQLiteWriter : IWriter -{ - private HashSet m_TypeSet = new (); - - private int m_CurrentAssetBundleId = -1; - private int m_NextAssetBundleId = 0; - - private string m_DatabaseName; - private bool m_SkipReferences; - - private Util.IdProvider m_SerializedFileIdProvider = new (); - private Util.ObjectIdProvider m_ObjectIdProvider = new (); - - private Regex m_RegexSceneFile = new(@"BuildPlayer-([^\.]+)(?:\.sharedAssets)?"); - - // Used to map PPtr fileId to its corresponding serialized file id in the database. - Dictionary m_LocalToDbFileId = new (); - - private Dictionary m_Handlers = new () - { - { "Mesh", new MeshHandler() }, - { "Texture2D", new Texture2DHandler() }, - { "Shader", new ShaderHandler() }, - { "AudioClip", new AudioClipHandler() }, - { "AnimationClip", new AnimationClipHandler() }, - { "AssetBundle", new AssetBundleHandler() }, - { "PreloadData", new PreloadDataHandler() }, - }; - - private SqliteConnection m_Database; - private SqliteCommand m_AddReferenceCommand = new SqliteCommand(); - private SqliteCommand m_AddAssetBundleCommand = new SqliteCommand(); - private SqliteCommand m_AddSerializedFileCommand = new SqliteCommand(); - private SqliteCommand m_AddObjectCommand = new SqliteCommand(); - private SqliteCommand m_AddTypeCommand = new SqliteCommand(); - private SqliteCommand m_InsertDepCommand = new SqliteCommand(); - private SqliteTransaction m_CurrentTransaction = null; - public SQLiteWriter(string databaseName, bool skipReferences) - { - m_DatabaseName = databaseName; - m_SkipReferences = skipReferences; - } - - public void Begin() - { - if (m_Database != null) - { - throw new InvalidOperationException("SQLiteWriter.Begin called twice"); - } - SqliteConnectionStringBuilder builder = new(); - builder.DataSource = m_DatabaseName; - builder.Mode = SqliteOpenMode.ReadWriteCreate; - m_Database = new SqliteConnection(builder.ConnectionString); - File.WriteAllBytes(m_DatabaseName, Array.Empty()); - try - { - m_Database.Open(); - } - catch (Exception e) - { - Console.Error.WriteLine($"Error creating database: {e.Message}"); - } - - using var command = m_Database.CreateCommand(); - command.CommandText = Properties.Resources.Init; - command.ExecuteNonQuery(); - - foreach (var handler in m_Handlers.Values) - { - // Console.WriteLine($"Init handler: {handler.GetType().Name}"); - // Console.WriteLine($"Connection state before init: {m_Database.State}"); - handler.Init(m_Database); - // Console.WriteLine($"Connection state after init: {m_Database.State}"); - - } - - CreateSQLiteCommands(); - } - - public void End() - { - if (m_Database == null) - { - throw new InvalidOperationException("SQLiteWriter.End called before SQLiteWriter.Begin"); - } - - foreach (var handler in m_Handlers.Values) - { - handler.Finalize(m_Database); - } - - using var finalizeCommand = m_Database.CreateCommand(); - finalizeCommand.CommandText = Properties.Resources.Finalize; - finalizeCommand.ExecuteNonQuery(); - } - - private void CreateSQLiteCommands() - { - m_AddAssetBundleCommand = m_Database.CreateCommand(); - m_AddAssetBundleCommand.CommandText = "INSERT INTO asset_bundles (id, name, file_size) VALUES (@id, @name, @file_size)"; - m_AddAssetBundleCommand.Parameters.Add("@id", SqliteType.Integer); - m_AddAssetBundleCommand.Parameters.Add("@name", SqliteType.Text); - m_AddAssetBundleCommand.Parameters.Add("@file_size", SqliteType.Integer); - - m_AddSerializedFileCommand = m_Database.CreateCommand(); - m_AddSerializedFileCommand.CommandText = "INSERT INTO serialized_files (id, asset_bundle, name) VALUES (@id, @asset_bundle, @name)"; - m_AddSerializedFileCommand.Parameters.Add("@id", SqliteType.Integer); - m_AddSerializedFileCommand.Parameters.Add("@asset_bundle", SqliteType.Integer); - m_AddSerializedFileCommand.Parameters.Add("@name", SqliteType.Text); - - m_AddReferenceCommand = m_Database.CreateCommand(); - m_AddReferenceCommand.CommandText = "INSERT INTO refs (object, referenced_object, property_path, property_type) VALUES (@object, @referenced_object, @property_path, @property_type)"; - m_AddReferenceCommand.Parameters.Add("@object", SqliteType.Integer); - m_AddReferenceCommand.Parameters.Add("@referenced_object", SqliteType.Integer); - m_AddReferenceCommand.Parameters.Add("@property_path", SqliteType.Text); - m_AddReferenceCommand.Parameters.Add("@property_type", SqliteType.Text); - - m_AddObjectCommand = m_Database.CreateCommand(); - m_AddObjectCommand.CommandText = "INSERT INTO objects (id, object_id, serialized_file, type, name, game_object, size, crc32) VALUES (@id, @object_id, @serialized_file, @type, @name, @game_object, @size, @crc32)"; - m_AddObjectCommand.Parameters.Add("@id", SqliteType.Integer); - m_AddObjectCommand.Parameters.Add("@object_id", SqliteType.Integer); - m_AddObjectCommand.Parameters.Add("@serialized_file", SqliteType.Integer); - m_AddObjectCommand.Parameters.Add("@type", SqliteType.Integer); - m_AddObjectCommand.Parameters.Add("@name", SqliteType.Text); - m_AddObjectCommand.Parameters.Add("@game_object", SqliteType.Integer); - m_AddObjectCommand.Parameters.Add("@size", SqliteType.Integer); - m_AddObjectCommand.Parameters.Add("@crc32", SqliteType.Integer); - - m_AddTypeCommand = m_Database.CreateCommand(); - m_AddTypeCommand.CommandText = "INSERT INTO types (id, name) VALUES (@id, @name)"; - m_AddTypeCommand.Parameters.Add("@id", SqliteType.Integer); - m_AddTypeCommand.Parameters.Add("@name", SqliteType.Text); - - m_InsertDepCommand = m_Database.CreateCommand(); - m_InsertDepCommand.CommandText = "INSERT INTO asset_dependencies(object, dependency) VALUES(@object, @dependency)"; - m_InsertDepCommand.Parameters.Add("@object", SqliteType.Integer); - m_InsertDepCommand.Parameters.Add("@dependency", SqliteType.Integer); - } - - public void BeginAssetBundle(string name, long size) - { - if (m_CurrentAssetBundleId != -1) - { - throw new InvalidOperationException("SQLWriter.BeginAssetBundle called twice"); - } - - m_CurrentAssetBundleId = m_NextAssetBundleId++; - m_AddAssetBundleCommand.Parameters["@id"].Value = m_CurrentAssetBundleId; - m_AddAssetBundleCommand.Parameters["@name"].Value = name; - m_AddAssetBundleCommand.Parameters["@file_size"].Value = size; - m_AddAssetBundleCommand.ExecuteNonQuery(); - } - - public void EndAssetBundle() - { - if (m_CurrentAssetBundleId == -1) - { - throw new InvalidOperationException("SQLWriter.EndAssetBundle called before SQLWriter.BeginAssetBundle"); - } - - m_CurrentAssetBundleId = -1; - } - - public void WriteSerializedFile(string relativePath, string fullPath, string containingFolder) - { - 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()); - int sceneId = -1; - - using var transaction = m_Database.BeginTransaction(); - m_CurrentTransaction = transaction; - - var match = m_RegexSceneFile.Match(relativePath); - - if (match.Success) - { - var sceneName = match.Groups[1].Value; - - // 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)); - - // There are 2 SerializedFiles per Scene, one ends with .sharedAssets. This is a - // dirty trick to avoid inserting the scene object a second time. - if (relativePath.EndsWith(".sharedAssets")) - { - m_AddObjectCommand.Transaction = transaction; - m_AddObjectCommand.Parameters["@game_object"].Value = ""; // There is no asscociated GameObject - m_AddObjectCommand.Parameters["@id"].Value = sceneId; - m_AddObjectCommand.Parameters["@object_id"].Value = 0; - m_AddObjectCommand.Parameters["@serialized_file"].Value = serializedFileId; - // The type is set to -1 which doesn't exist in Unity, but is associated to - // "Scene" in the database. - m_AddObjectCommand.Parameters["@type"].Value = -1; - m_AddObjectCommand.Parameters["@name"].Value = sceneName; - m_AddObjectCommand.Parameters["@size"].Value = 0; - m_AddObjectCommand.Parameters["@crc32"].Value = 0; - m_AddObjectCommand.ExecuteNonQuery(); - } - } - - m_LocalToDbFileId.Clear(); - - Context ctx = new() - { - AssetBundleId = m_CurrentAssetBundleId, - SerializedFileId = serializedFileId, - SceneId = sceneId, - ObjectIdProvider = m_ObjectIdProvider, - SerializedFileIdProvider = m_SerializedFileIdProvider, - LocalToDbFileId = m_LocalToDbFileId, - Transaction = transaction, - }; - - ctx.Transaction = transaction; - try - { - m_AddSerializedFileCommand.Transaction = transaction; - m_AddSerializedFileCommand.Parameters["@id"].Value = serializedFileId; - m_AddSerializedFileCommand.Parameters["@asset_bundle"].Value = m_CurrentAssetBundleId == -1 ? "" : m_CurrentAssetBundleId; - m_AddSerializedFileCommand.Parameters["@name"].Value = relativePath; - m_AddSerializedFileCommand.ExecuteNonQuery(); - - int localId = 0; - 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())); - } - - foreach (var obj in sf.Objects) - { - var currentObjectId = m_ObjectIdProvider.GetId((serializedFileId, obj.Id)); - // Console.WriteLine($"\nProcessing {currentObjectId}"); - var root = sf.GetTypeTreeRoot(obj.Id); - var offset = obj.Offset; - uint crc32 = 0; - - if (!m_TypeSet.Contains(obj.TypeId)) - { - m_AddTypeCommand.Transaction = transaction; - m_AddTypeCommand.Parameters["@id"].Value = obj.TypeId; - m_AddTypeCommand.Parameters["@name"].Value = root.Type; - m_AddTypeCommand.ExecuteNonQuery(); - - m_TypeSet.Add(obj.TypeId); - } - - var randomAccessReader = new RandomAccessReader(sf, root, reader, offset); - - string name = string.Empty; - long streamDataSize = 0; - - if (m_Handlers.TryGetValue(root.Type, out var handler)) - { - handler.Process(ctx, currentObjectId, randomAccessReader, - out name, out streamDataSize); - } - else if (randomAccessReader.HasChild("m_Name")) - { - name = randomAccessReader["m_Name"].GetValue(); - } - - if (randomAccessReader.HasChild("m_GameObject")) - { - var pptr = randomAccessReader["m_GameObject"]; - var fileId = m_LocalToDbFileId[pptr["m_FileID"].GetValue()]; - var gameObjectID = m_ObjectIdProvider.GetId((fileId, pptr["m_PathID"].GetValue())); - m_AddObjectCommand.Parameters["@game_object"].Value = gameObjectID; - } - else - { - m_AddObjectCommand.Parameters["@game_object"].Value = ""; - } - - if (!m_SkipReferences) - { - crc32 = pptrReader.Process(currentObjectId, offset, root); - } - - m_AddObjectCommand.Parameters["@id"].Value = currentObjectId; - m_AddObjectCommand.Parameters["@object_id"].Value = obj.Id; - m_AddObjectCommand.Parameters["@serialized_file"].Value = serializedFileId; - m_AddObjectCommand.Parameters["@type"].Value = obj.TypeId; - m_AddObjectCommand.Parameters["@name"].Value = name; - m_AddObjectCommand.Parameters["@size"].Value = obj.Size + streamDataSize; - m_AddObjectCommand.Parameters["@crc32"].Value = crc32; - m_AddObjectCommand.Transaction = transaction; - m_AddObjectCommand.ExecuteNonQuery(); - - // If this is a Scene AssetBundle, add the object as a depencency of the - // current scene. - if (ctx.SceneId != -1) - { - m_InsertDepCommand.Parameters["@object"].Value = ctx.SceneId; - m_InsertDepCommand.Parameters["@dependency"].Value = currentObjectId; - m_InsertDepCommand.Transaction = transaction; - m_InsertDepCommand.ExecuteNonQuery(); - } - } - - transaction.Commit(); - } - catch (Exception) - { - transaction.Rollback(); - throw; - } - } - - private int AddReference(long objectId, int fileId, long pathId, string propertyPath, string propertyType) - { - var referencedObjectId = m_ObjectIdProvider.GetId((m_LocalToDbFileId[fileId], pathId)); - m_AddReferenceCommand.Transaction = m_CurrentTransaction; - m_AddReferenceCommand.Parameters["@object"].Value = objectId; - m_AddReferenceCommand.Parameters["@referenced_object"].Value = referencedObjectId; - m_AddReferenceCommand.Parameters["@property_path"].Value = propertyPath; - m_AddReferenceCommand.Parameters["@property_type"].Value = propertyType; - m_AddReferenceCommand.ExecuteNonQuery(); - - return referencedObjectId; - } - - public void Dispose() - { - foreach (var handler in m_Handlers.Values) - { - handler.Dispose(); - } - - m_AddAssetBundleCommand.Dispose(); - m_AddSerializedFileCommand.Dispose(); - m_AddReferenceCommand.Dispose(); - m_AddObjectCommand.Dispose(); - m_AddTypeCommand.Dispose(); - m_InsertDepCommand.Dispose(); - - m_Database.Dispose(); - } -} diff --git a/Analyzer/SQLite/Writers/AddressablesBuildLayoutSQLWriter.cs b/Analyzer/SQLite/Writers/AddressablesBuildLayoutSQLWriter.cs new file mode 100644 index 0000000..4d5b9a3 --- /dev/null +++ b/Analyzer/SQLite/Writers/AddressablesBuildLayoutSQLWriter.cs @@ -0,0 +1,582 @@ +using Analyzer.SQLite.Commands.AddressablesBuildReport; +using Microsoft.Data.Sqlite; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityDataTools.Analyzer.Build; + +namespace Analyzer.SQLite.Writers +{ + internal class AddressablesBuildLayoutSQLWriter : IDisposable + { + private AddressablesBuild m_AddressablesBuild = new AddressablesBuild(); + private AddressablesBuildBundle m_AddressablesBuildBundle = new AddressablesBuildBundle(); + private AddressablesBuildBundleDependency m_AddressablesBuildBundleDependency = new AddressablesBuildBundleDependency(); + private AddressablesBuildBundleExpandedDependency m_AddressablesBuildBundleExpandedDependency = new AddressablesBuildBundleExpandedDependency(); + private AddressablesBuildBundleRegularDependency m_AddressablesBuildBundleRegularDependency = new AddressablesBuildBundleRegularDependency(); + private AddressablesBuildBundleDependentBundle m_AddressablesBuildBundleDependentBundle = new AddressablesBuildBundleDependentBundle(); + private AddressablesBuildBundleFile m_AddressablesBuildBundleFile = new AddressablesBuildBundleFile(); + + private AddressablesBuildDataFromOtherAsset m_AddressablesDataFromOtherAsset = new AddressablesBuildDataFromOtherAsset(); + private AddressablesBuildDataFromOtherAssetObject m_AddressablesBuildDataFromOtherAssetObject = new AddressablesBuildDataFromOtherAssetObject(); + private AddressablesBuildDataFromOtherAssetObjectReference m_AddressablesBuildDataFromOtherAssetObjectReference = new AddressablesBuildDataFromOtherAssetObjectReference(); + private AddressablesBuildDataFromOtherAssetReferencingAsset m_AddressablesBuildDataFromOtherAssetReferencingAsset = new AddressablesBuildDataFromOtherAssetReferencingAsset(); + + private AddressablesBuildExplicitAsset m_AddressablesExplicitAsset = new AddressablesBuildExplicitAsset(); + private AddressablesBuildExplicitAssetExternallyReferencedAsset m_AddressablesBuildExplicitAssetExternallyReferencedAsset = new AddressablesBuildExplicitAssetExternallyReferencedAsset(); + private AddressablesBuildExplicitAssetInternalReferencedExplicitAsset m_AddressablesBuildExplicitAssetInternalReferencedExplicitAsset = new AddressablesBuildExplicitAssetInternalReferencedExplicitAsset(); + private AddressablesBuildExplicitAssetInternalReferencedOtherAsset m_AddressablesBuildExplicitAssetInternalReferencedOtherAsset = new AddressablesBuildExplicitAssetInternalReferencedOtherAsset(); + private AddressablesBuildExplicitAssetLabel m_AddressablesBuildExplicitAssetLabel = new AddressablesBuildExplicitAssetLabel(); + + private AddressablesBuildFile m_AddressablesBuildFile = new AddressablesBuildFile(); + private AddressablesBuildFileAsset m_AddressablesBuildFileAsset = new AddressablesBuildFileAsset(); + private AddressablesBuildFileExternalReference m_AddressablesBuildFileExternalReference = new AddressablesBuildFileExternalReference(); + private AddressablesBuildFileOtherAsset m_AddressablesBuildFileOtherAsset = new AddressablesBuildFileOtherAsset(); + private AddressablesBuildFileSubFile m_AddressablesBuildFileSubFile = new AddressablesBuildFileSubFile(); + + private AddressablesBuildGroup m_AddressablesBuildGroup = new AddressablesBuildGroup(); + private AddressablesBuildGroupBundle m_AddressablesBuildGroupBundle = new AddressablesBuildGroupBundle(); + private AddressablesBuildGroupSchema m_AddressablesBuildGroupSchema = new AddressablesBuildGroupSchema(); + + private AddressablesBuildSchema m_AddressablesBuildSchema = new AddressablesBuildSchema(); + private AddressablesBuildSchemaDataPair m_AddressablesBuildSchemaDataPair = new AddressablesBuildSchemaDataPair(); + + private AddressablesBuildSubFile m_AddressablesBuildSubFile = new AddressablesBuildSubFile(); + + private SqliteCommand m_LastId = new SqliteCommand(); + + private string m_DatabaseName; + private SqliteConnection m_Database; + + public AddressablesBuildLayoutSQLWriter(SqliteConnection database) + { + m_Database = database; + } + + public void Init() + { + // build addressables file commands + m_AddressablesBuild.CreateCommand(m_Database); + // Build Bundle Tables + m_AddressablesBuildBundle.CreateCommand(m_Database); + m_AddressablesBuildBundleDependency.CreateCommand(m_Database); + m_AddressablesBuildBundleExpandedDependency.CreateCommand(m_Database); + m_AddressablesBuildBundleRegularDependency.CreateCommand(m_Database); + m_AddressablesBuildBundleDependentBundle.CreateCommand(m_Database); + m_AddressablesBuildBundleFile.CreateCommand(m_Database); + + // Data From Other Asset Tables + m_AddressablesDataFromOtherAsset.CreateCommand(m_Database); + m_AddressablesBuildDataFromOtherAssetObject.CreateCommand(m_Database); + m_AddressablesBuildDataFromOtherAssetObjectReference.CreateCommand(m_Database); + m_AddressablesBuildDataFromOtherAssetReferencingAsset.CreateCommand(m_Database); + + // Explicit Asset Tables + m_AddressablesExplicitAsset.CreateCommand(m_Database); + m_AddressablesBuildExplicitAssetExternallyReferencedAsset.CreateCommand(m_Database); + m_AddressablesBuildExplicitAssetInternalReferencedExplicitAsset.CreateCommand(m_Database); + m_AddressablesBuildExplicitAssetInternalReferencedOtherAsset.CreateCommand(m_Database); + m_AddressablesBuildExplicitAssetLabel.CreateCommand(m_Database); + + // File Tables + m_AddressablesBuildFile.CreateCommand(m_Database); + m_AddressablesBuildFileAsset.CreateCommand(m_Database); + m_AddressablesBuildFileExternalReference.CreateCommand(m_Database); + m_AddressablesBuildFileOtherAsset.CreateCommand(m_Database); + m_AddressablesBuildFileSubFile.CreateCommand(m_Database); + + // Group Tables + m_AddressablesBuildGroup.CreateCommand(m_Database); + m_AddressablesBuildGroupBundle.CreateCommand(m_Database); + m_AddressablesBuildGroupSchema.CreateCommand(m_Database); + + // Schema Tables + m_AddressablesBuildSchema.CreateCommand(m_Database); + m_AddressablesBuildSchemaDataPair.CreateCommand(m_Database); + + // SubFile Tables + m_AddressablesBuildSubFile.CreateCommand(m_Database); + + m_LastId = m_Database.CreateCommand(); + m_LastId.CommandText = "SELECT last_insert_rowid()"; + } + + public void Dispose() + { + // build addressables file commands + m_AddressablesBuild.Dispose(); + // Build Bundle Tables + m_AddressablesBuildBundle.Dispose(); + m_AddressablesBuildBundleDependency.Dispose(); + m_AddressablesBuildBundleExpandedDependency.Dispose(); + m_AddressablesBuildBundleRegularDependency.Dispose(); + m_AddressablesBuildBundleDependentBundle.Dispose(); + m_AddressablesBuildBundleFile.Dispose(); + + // Data From Other Asset Tables + m_AddressablesDataFromOtherAsset.Dispose(); + m_AddressablesBuildDataFromOtherAssetObject.Dispose(); + m_AddressablesBuildDataFromOtherAssetObjectReference.Dispose(); + m_AddressablesBuildDataFromOtherAssetReferencingAsset.Dispose(); + + // Explicit Asset Tables + m_AddressablesExplicitAsset.Dispose(); + m_AddressablesBuildExplicitAssetExternallyReferencedAsset.Dispose(); + m_AddressablesBuildExplicitAssetInternalReferencedExplicitAsset.Dispose(); + m_AddressablesBuildExplicitAssetInternalReferencedOtherAsset.Dispose(); + m_AddressablesBuildExplicitAssetLabel.Dispose(); + + // File Tables + m_AddressablesBuildFile.Dispose(); + m_AddressablesBuildFileAsset.Dispose(); + m_AddressablesBuildFileExternalReference.Dispose(); + m_AddressablesBuildFileOtherAsset.Dispose(); + m_AddressablesBuildFileSubFile.Dispose(); + + // Group Tables + m_AddressablesBuildGroup.Dispose(); + m_AddressablesBuildGroupBundle.Dispose(); + m_AddressablesBuildGroupSchema.Dispose(); + + // Schema Tables + m_AddressablesBuildSchema.Dispose(); + m_AddressablesBuildSchemaDataPair.Dispose(); + + // SubFile Tables + m_AddressablesBuildSubFile.Dispose(); + + m_LastId.Dispose(); + } + + public void WriteAddressablesBuild(string filename, BuildLayout buildLayout) + { + using var transaction = m_Database.BeginTransaction(); + + try + { + m_AddressablesBuild.SetTransaction(transaction); + m_AddressablesBuild.SetValue("name", Path.GetFileName(filename)); + m_AddressablesBuild.SetValue("build_target", buildLayout.BuildTarget); + m_AddressablesBuild.SetValue("start_time", buildLayout.BuildStartTime); + m_AddressablesBuild.SetValue("duration", buildLayout.Duration); + m_AddressablesBuild.SetValue("error", buildLayout.BuildError); + m_AddressablesBuild.SetValue("package_version", buildLayout.PackageVersion); + m_AddressablesBuild.SetValue("player_version", buildLayout.PlayerBuildVersion); + m_AddressablesBuild.SetValue("build_script", buildLayout.BuildScript); + m_AddressablesBuild.SetValue("result_hash", buildLayout.BuildResultHash); + m_AddressablesBuild.SetValue("type", buildLayout.BuildType); + m_AddressablesBuild.SetValue("unity_version", buildLayout.UnityVersion); + m_AddressablesBuild.ExecuteNonQuery(); + + m_LastId.Transaction = transaction; + long buildId = (long)m_LastId.ExecuteScalar(); + Console.WriteLine($"Build ID: {buildId}"); + + foreach (var reference in buildLayout.references.RefIds) + { + switch (reference.type.Class) + { + case "BuildLayout/Bundle": + WriteBuildLayoutBundle(reference, buildId, transaction); + break; + + case "BuildLayout/DataFromOtherAsset": + WriteBuildLayoutDataFromOtherAsset(reference, buildId, transaction); + break; + + case "BuildLayout/ExplicitAsset": + WriteBuildLayoutExplicitAsset(reference, buildId, transaction); + break; + + case "BuildLayout/File": + WriteBuildLayoutFile(reference, buildId, transaction); + break; + + case "BuildLayout/Group": + WriteBuildLayoutGroup(reference, buildId, transaction); + break; + + case "BuildLayout/SchemaData": + WriteBuildLayoutSchemaData(reference, buildId, transaction); + break; + + case "BuildLayout/SubFile": + WriteBuildLayoutSubFile(reference, buildId, transaction); + break; + } + } + + // do the stuff + transaction.Commit(); + } + catch (Exception e) + { + Console.WriteLine(e.StackTrace.ToString()); + transaction.Rollback(); + throw; + } + } + + private void WriteBuildLayoutBundle(Reference reference, long buildId, SqliteTransaction transaction) + { + m_AddressablesBuildBundle.SetTransaction(transaction); + m_AddressablesBuildBundle.SetValue("id", reference.rid); + m_AddressablesBuildBundle.SetValue("build_id", buildId); + m_AddressablesBuildBundle.SetValue("asset_count", reference.data.AssetCount); + m_AddressablesBuildBundle.SetValue("build_status", reference.data.BuildStatus); + m_AddressablesBuildBundle.SetValue("crc", reference.data.CRC); + m_AddressablesBuildBundle.SetValue("compression", reference.data.Compression); + m_AddressablesBuildBundle.SetValue("dependency_file_size", reference.data.DependencyFileSize); + m_AddressablesBuildBundle.SetValue("expanded_dependency_file_size", reference.data.ExpandedDependencyFileSize); + m_AddressablesBuildBundle.SetValue("file_size", reference.data.FileSize); + m_AddressablesBuildBundle.SetValue("group_rid", reference.data.Group.rid); + m_AddressablesBuildBundle.SetValue("hash", JsonConvert.SerializeObject(reference.data.Hash)); + m_AddressablesBuildBundle.SetValue("internal_name", reference.data.InternalName); + m_AddressablesBuildBundle.SetValue("load_path", reference.data.LoadPath); + m_AddressablesBuildBundle.SetValue("name", reference.data.Name); + m_AddressablesBuildBundle.SetValue("provider", reference.data.Provider); + m_AddressablesBuildBundle.SetValue("result_type", reference.data.ResultType); + m_AddressablesBuildBundle.ExecuteNonQuery(); + + // Insert bundle dependencies + if (reference.data.BundleDependencies != null) + { + foreach (var dep in reference.data.BundleDependencies) + { + m_AddressablesBuildBundleDependency.SetTransaction(transaction); + m_AddressablesBuildBundleDependency.SetValue("bundle_id", reference.rid); + m_AddressablesBuildBundleDependency.SetValue("build_id", buildId); + m_AddressablesBuildBundleDependency.SetValue("dependency_rid", dep.rid); + m_AddressablesBuildBundleDependency.ExecuteNonQuery(); + } + } + + // Insert regular dependencies + if (reference.data.Dependencies != null) + { + foreach (var dep in reference.data.Dependencies) + { + m_AddressablesBuildBundleRegularDependency.SetTransaction(transaction); + m_AddressablesBuildBundleRegularDependency.SetValue("bundle_id", reference.rid); + m_AddressablesBuildBundleRegularDependency.SetValue("build_id", buildId); + m_AddressablesBuildBundleRegularDependency.SetValue("dependency_rid", dep.rid); + m_AddressablesBuildBundleRegularDependency.ExecuteNonQuery(); + } + } + + // Insert dependent bundles + if (reference.data.DependentBundles != null) + { + foreach (var depBundle in reference.data.DependentBundles) + { + m_AddressablesBuildBundleDependentBundle.SetTransaction(transaction); + m_AddressablesBuildBundleDependentBundle.SetValue("bundle_id", reference.rid); + m_AddressablesBuildBundleDependentBundle.SetValue("build_id", buildId); + m_AddressablesBuildBundleDependentBundle.SetValue("dependent_bundle_rid", depBundle.rid); + m_AddressablesBuildBundleDependentBundle.ExecuteNonQuery(); + } + } + + // Insert expanded dependencies + if (reference.data.ExpandedDependencies != null) + { + foreach (var dep in reference.data.ExpandedDependencies) + { + m_AddressablesBuildBundleExpandedDependency.SetTransaction(transaction); + m_AddressablesBuildBundleExpandedDependency.SetValue("bundle_id", reference.rid); + m_AddressablesBuildBundleExpandedDependency.SetValue("build_id", buildId); + m_AddressablesBuildBundleExpandedDependency.SetValue("dependency_rid", dep.rid); + m_AddressablesBuildBundleExpandedDependency.ExecuteNonQuery(); + } + } + + // Insert files + if (reference.data.Files != null) + { + foreach (var file in reference.data.Files) + { + m_AddressablesBuildBundleFile.SetTransaction(transaction); + m_AddressablesBuildBundleFile.SetValue("bundle_id", reference.rid); + m_AddressablesBuildBundleFile.SetValue("build_id", buildId); + m_AddressablesBuildBundleFile.SetValue("file_rid", file.rid); + m_AddressablesBuildBundleFile.ExecuteNonQuery(); + } + } + } + + private void WriteBuildLayoutDataFromOtherAsset(Reference reference, long buildId, SqliteTransaction transaction) + { + m_AddressablesDataFromOtherAsset.SetTransaction(transaction); + m_AddressablesDataFromOtherAsset.SetValue("id", reference.rid); + m_AddressablesDataFromOtherAsset.SetValue("build_id", buildId); + m_AddressablesDataFromOtherAsset.SetValue("asset_guid", reference.data.AssetGuid); + m_AddressablesDataFromOtherAsset.SetValue("asset_path", reference.data.AssetPath); + m_AddressablesDataFromOtherAsset.SetValue("file", reference.data.File.rid); + m_AddressablesDataFromOtherAsset.SetValue("main_asset_type", reference.data.MainAssetType); + m_AddressablesDataFromOtherAsset.SetValue("object_count", reference.data.ObjectCount); + m_AddressablesDataFromOtherAsset.SetValue("serialized_size", reference.data.SerializedSize); + m_AddressablesDataFromOtherAsset.SetValue("streamed_size", reference.data.StreamedSize); + m_AddressablesDataFromOtherAsset.ExecuteNonQuery(); + + // Insert objects + if (reference.data.Objects != null) + { + foreach (var obj in reference.data.Objects) + { + m_AddressablesBuildDataFromOtherAssetObject.SetTransaction(transaction); + m_AddressablesBuildDataFromOtherAssetObject.SetValue("data_from_other_asset_id", reference.rid); + m_AddressablesBuildDataFromOtherAssetObject.SetValue("build_id", buildId); + m_AddressablesBuildDataFromOtherAssetObject.SetValue("asset_type", obj.AssetType); + m_AddressablesBuildDataFromOtherAssetObject.SetValue("component_name", obj.ComponentName ?? ""); + m_AddressablesBuildDataFromOtherAssetObject.SetValue("local_identifier_in_file", obj.LocalIdentifierInFile); + m_AddressablesBuildDataFromOtherAssetObject.SetValue("object_name", obj.ObjectName ?? ""); + m_AddressablesBuildDataFromOtherAssetObject.SetValue("serialized_size", obj.SerializedSize); + m_AddressablesBuildDataFromOtherAssetObject.SetValue("streamed_size", obj.StreamedSize); + m_AddressablesBuildDataFromOtherAssetObject.ExecuteNonQuery(); + + // Insert object references + if (obj.References != null) + { + foreach (var objRef in obj.References) + { + m_AddressablesBuildDataFromOtherAssetObjectReference.SetTransaction(transaction); + m_AddressablesBuildDataFromOtherAssetObjectReference.SetValue("data_from_other_asset_id", reference.rid); + m_AddressablesBuildDataFromOtherAssetObjectReference.SetValue("build_id", buildId); + m_AddressablesBuildDataFromOtherAssetObjectReference.SetValue("local_identifier_in_file", obj.LocalIdentifierInFile); + m_AddressablesBuildDataFromOtherAssetObjectReference.SetValue("asset_id", objRef.AssetId); + m_AddressablesBuildDataFromOtherAssetObjectReference.SetValue("object_id", objRef.ObjectId); + m_AddressablesBuildDataFromOtherAssetObjectReference.ExecuteNonQuery(); + } + } + } + } + + // Insert referencing assets + if (reference.data.ReferencingAssets != null) + { + foreach (var refAsset in reference.data.ReferencingAssets) + { + m_AddressablesBuildDataFromOtherAssetReferencingAsset.SetTransaction(transaction); + m_AddressablesBuildDataFromOtherAssetReferencingAsset.SetValue("data_from_other_asset_id", reference.rid); + m_AddressablesBuildDataFromOtherAssetReferencingAsset.SetValue("build_id", buildId); + m_AddressablesBuildDataFromOtherAssetReferencingAsset.SetValue("referencing_asset_rid", refAsset.rid); + m_AddressablesBuildDataFromOtherAssetReferencingAsset.ExecuteNonQuery(); + } + } + } + + private void WriteBuildLayoutExplicitAsset(Reference reference, long buildId, SqliteTransaction transaction) + { + m_AddressablesExplicitAsset.SetTransaction(transaction); + m_AddressablesExplicitAsset.SetValue("id", reference.rid); + m_AddressablesExplicitAsset.SetValue("build_id", buildId); + m_AddressablesExplicitAsset.SetValue("bundle", reference.data.Bundle.rid); + m_AddressablesExplicitAsset.SetValue("file", reference.data.File.rid); + m_AddressablesExplicitAsset.SetValue("asset_hash", reference.data.AssetHash.Hash); + m_AddressablesExplicitAsset.SetValue("asset_path", reference.data.AssetPath); + m_AddressablesExplicitAsset.SetValue("addressable_name", reference.data.AddressableName); + m_AddressablesExplicitAsset.SetValue("group_guid", reference.data.GroupGuid); + m_AddressablesExplicitAsset.SetValue("guid", reference.data.Guid); + m_AddressablesExplicitAsset.SetValue("internal_id", reference.data.InternalId); + m_AddressablesExplicitAsset.SetValue("streamed_size", reference.data.StreamedSize); + m_AddressablesExplicitAsset.SetValue("serialized_size", reference.data.SerializedSize); + m_AddressablesExplicitAsset.SetValue("main_asset_type", reference.data.MainAssetType); + m_AddressablesExplicitAsset.ExecuteNonQuery(); + + // Insert externally referenced assets + if (reference.data.ExternallyReferencedAssets != null) + { + foreach (var extRefAsset in reference.data.ExternallyReferencedAssets) + { + m_AddressablesBuildExplicitAssetExternallyReferencedAsset.SetTransaction(transaction); + m_AddressablesBuildExplicitAssetExternallyReferencedAsset.SetValue("explicit_asset_id", reference.rid); + m_AddressablesBuildExplicitAssetExternallyReferencedAsset.SetValue("build_id", buildId); + m_AddressablesBuildExplicitAssetExternallyReferencedAsset.SetValue("externally_referenced_asset_rid", extRefAsset.rid); + m_AddressablesBuildExplicitAssetExternallyReferencedAsset.ExecuteNonQuery(); + } + } + + // Insert internal referenced explicit assets + if (reference.data.InternalReferencedExplicitAssets != null) + { + foreach (var intRefExplicitAsset in reference.data.InternalReferencedExplicitAssets) + { + m_AddressablesBuildExplicitAssetInternalReferencedExplicitAsset.SetTransaction(transaction); + m_AddressablesBuildExplicitAssetInternalReferencedExplicitAsset.SetValue("explicit_asset_id", reference.rid); + m_AddressablesBuildExplicitAssetInternalReferencedExplicitAsset.SetValue("build_id", buildId); + m_AddressablesBuildExplicitAssetInternalReferencedExplicitAsset.SetValue("internal_referenced_explicit_asset_rid", intRefExplicitAsset.rid); + m_AddressablesBuildExplicitAssetInternalReferencedExplicitAsset.ExecuteNonQuery(); + } + } + + // Insert internal referenced other assets + if (reference.data.InternalReferencedOtherAssets != null) + { + foreach (var intRefOtherAsset in reference.data.InternalReferencedOtherAssets) + { + m_AddressablesBuildExplicitAssetInternalReferencedOtherAsset.SetTransaction(transaction); + m_AddressablesBuildExplicitAssetInternalReferencedOtherAsset.SetValue("explicit_asset_id", reference.rid); + m_AddressablesBuildExplicitAssetInternalReferencedOtherAsset.SetValue("build_id", buildId); + m_AddressablesBuildExplicitAssetInternalReferencedOtherAsset.SetValue("internal_referenced_other_asset_rid", intRefOtherAsset.rid); + m_AddressablesBuildExplicitAssetInternalReferencedOtherAsset.ExecuteNonQuery(); + } + } + + // Insert labels + if (reference.data.Labels != null) + { + foreach (var label in reference.data.Labels) + { + m_AddressablesBuildExplicitAssetLabel.SetTransaction(transaction); + m_AddressablesBuildExplicitAssetLabel.SetValue("explicit_asset_id", reference.rid); + m_AddressablesBuildExplicitAssetLabel.SetValue("build_id", buildId); + m_AddressablesBuildExplicitAssetLabel.SetValue("label", label); + m_AddressablesBuildExplicitAssetLabel.ExecuteNonQuery(); + } + } + } + + private void WriteBuildLayoutFile(Reference reference, long buildId, SqliteTransaction transaction) + { + m_AddressablesBuildFile.SetTransaction(transaction); + m_AddressablesBuildFile.SetValue("id", reference.rid); + m_AddressablesBuildFile.SetValue("build_id", buildId); + m_AddressablesBuildFile.SetValue("bundle", reference.data.Bundle.rid); + m_AddressablesBuildFile.SetValue("bundle_object_info_size", reference.data.BundleObjectInfo.Size); + m_AddressablesBuildFile.SetValue("mono_script_count", reference.data.MonoScriptCount); + m_AddressablesBuildFile.SetValue("mono_script_size", reference.data.MonoScriptSize); + m_AddressablesBuildFile.SetValue("name", reference.data.Name); + m_AddressablesBuildFile.SetValue("preload_info_size", reference.data.PreloadInfoSize); + m_AddressablesBuildFile.SetValue("write_result_filename", reference.data.WriteResultFilename); + m_AddressablesBuildFile.ExecuteNonQuery(); + + // Insert assets + if (reference.data.Assets != null) + { + foreach (var asset in reference.data.Assets) + { + m_AddressablesBuildFileAsset.SetTransaction(transaction); + m_AddressablesBuildFileAsset.SetValue("file_id", reference.rid); + m_AddressablesBuildFileAsset.SetValue("build_id", buildId); + m_AddressablesBuildFileAsset.SetValue("asset_rid", asset.rid); + m_AddressablesBuildFileAsset.ExecuteNonQuery(); + } + } + + // Insert external references + if (reference.data.ExternalReferences != null) + { + foreach (var extRef in reference.data.ExternalReferences) + { + m_AddressablesBuildFileExternalReference.SetTransaction(transaction); + m_AddressablesBuildFileExternalReference.SetValue("file_id", reference.rid); + m_AddressablesBuildFileExternalReference.SetValue("build_id", buildId); + m_AddressablesBuildFileExternalReference.SetValue("external_reference_rid", extRef.rid); + m_AddressablesBuildFileExternalReference.ExecuteNonQuery(); + } + } + + // Insert other assets + if (reference.data.OtherAssets != null) + { + foreach (var otherAsset in reference.data.OtherAssets) + { + m_AddressablesBuildFileOtherAsset.SetTransaction(transaction); + m_AddressablesBuildFileOtherAsset.SetValue("file_id", reference.rid); + m_AddressablesBuildFileOtherAsset.SetValue("build_id", buildId); + m_AddressablesBuildFileOtherAsset.SetValue("other_asset_rid", otherAsset.rid); + m_AddressablesBuildFileOtherAsset.ExecuteNonQuery(); + } + } + + // Insert sub files + if (reference.data.SubFiles != null) + { + foreach (var subFile in reference.data.SubFiles) + { + m_AddressablesBuildFileSubFile.SetTransaction(transaction); + m_AddressablesBuildFileSubFile.SetValue("file_id", reference.rid); + m_AddressablesBuildFileSubFile.SetValue("build_id", buildId); + m_AddressablesBuildFileSubFile.SetValue("sub_file_rid", subFile.rid); + m_AddressablesBuildFileSubFile.ExecuteNonQuery(); + } + } + } + + private void WriteBuildLayoutGroup(Reference reference, long buildId, SqliteTransaction transaction) + { + m_AddressablesBuildGroup.SetTransaction(transaction); + m_AddressablesBuildGroup.SetValue("id", reference.rid); + m_AddressablesBuildGroup.SetValue("build_id", buildId); + m_AddressablesBuildGroup.SetValue("guid", reference.data.Guid); + m_AddressablesBuildGroup.SetValue("name", reference.data.Name); + m_AddressablesBuildGroup.SetValue("packing_mode", reference.data.PackingMode); + m_AddressablesBuildGroup.ExecuteNonQuery(); + + // Insert bundles + if (reference.data.Bundles != null) + { + foreach (var bundle in reference.data.Bundles) + { + m_AddressablesBuildGroupBundle.SetTransaction(transaction); + m_AddressablesBuildGroupBundle.SetValue("group_id", reference.rid); + m_AddressablesBuildGroupBundle.SetValue("build_id", buildId); + m_AddressablesBuildGroupBundle.SetValue("bundle_rid", bundle.rid); + m_AddressablesBuildGroupBundle.ExecuteNonQuery(); + } + } + + // Insert schemas + if (reference.data.Schemas != null) + { + foreach (var schema in reference.data.Schemas) + { + m_AddressablesBuildGroupSchema.SetTransaction(transaction); + m_AddressablesBuildGroupSchema.SetValue("group_id", reference.rid); + m_AddressablesBuildGroupSchema.SetValue("build_id", buildId); + m_AddressablesBuildGroupSchema.SetValue("schema_rid", schema.rid); + m_AddressablesBuildGroupSchema.ExecuteNonQuery(); + } + } + } + + private void WriteBuildLayoutSchemaData(Reference reference, long buildId, SqliteTransaction transaction) + { + m_AddressablesBuildSchema.SetTransaction(transaction); + m_AddressablesBuildSchema.SetValue("id", reference.rid); + m_AddressablesBuildSchema.SetValue("build_id", buildId); + m_AddressablesBuildSchema.SetValue("guid", reference.data.Guid); + m_AddressablesBuildSchema.SetValue("type", reference.data.Type); + m_AddressablesBuildSchema.ExecuteNonQuery(); + + // Insert schema data pairs + if (reference.data.SchemaDataPairs != null) + { + foreach (var dataPair in reference.data.SchemaDataPairs) + { + m_AddressablesBuildSchemaDataPair.SetTransaction(transaction); + m_AddressablesBuildSchemaDataPair.SetValue("schema_id", reference.rid); + m_AddressablesBuildSchemaDataPair.SetValue("build_id", buildId); + m_AddressablesBuildSchemaDataPair.SetValue("key", dataPair.Key); + m_AddressablesBuildSchemaDataPair.SetValue("value", dataPair.Value); + m_AddressablesBuildSchemaDataPair.ExecuteNonQuery(); + } + } + } + + private void WriteBuildLayoutSubFile(Reference reference, long buildId, SqliteTransaction transaction) + { + m_AddressablesBuildSubFile.SetTransaction(transaction); + m_AddressablesBuildSubFile.SetValue("id", reference.rid); + m_AddressablesBuildSubFile.SetValue("build_id", buildId); + m_AddressablesBuildSubFile.SetValue("is_serialized_file", reference.data.IsSerializedFile ? 1 : 0); + m_AddressablesBuildSubFile.SetValue("name", reference.data.Name); + m_AddressablesBuildSubFile.SetValue("size", reference.data.Size); + m_AddressablesBuildSubFile.ExecuteNonQuery(); + } + } +} diff --git a/Analyzer/SQLite/Writers/AssetBundleSQLiteWriter.cs b/Analyzer/SQLite/Writers/AssetBundleSQLiteWriter.cs new file mode 100644 index 0000000..03a616d --- /dev/null +++ b/Analyzer/SQLite/Writers/AssetBundleSQLiteWriter.cs @@ -0,0 +1,287 @@ +using System; +using System.Collections.Generic; +using Microsoft.Data.Sqlite; +using System.IO; +using System.Text.RegularExpressions; +using UnityDataTools.Analyzer.SQLite.Handlers; +using UnityDataTools.FileSystem; +using UnityDataTools.FileSystem.TypeTreeReaders; +using UnityDataTools.Analyzer.SQLite.Commands.SerializedFile; +using UnityDataTools.Analyzer; +using UnityDataTools.Analyzer.Util; + +namespace Analyzer.SQLite.Writers; + +public class AssetBundleSQLiteWriter : IDisposable +{ + private HashSet m_TypeSet = new(); + + private int m_CurrentAssetBundleId = -1; + private int m_NextAssetBundleId = 0; + + private bool m_SkipReferences; + + private IdProvider m_SerializedFileIdProvider = new(); + private ObjectIdProvider m_ObjectIdProvider = new(); + + private Regex m_RegexSceneFile = new(@"BuildPlayer-([^\.]+)(?:\.sharedAssets)?"); + + // Used to map PPtr fileId to its corresponding serialized file id in the database. + Dictionary m_LocalToDbFileId = new (); + + private Dictionary m_Handlers = new() + { + { "Mesh", new MeshHandler() }, + { "Texture2D", new Texture2DHandler() }, + { "Shader", new ShaderHandler() }, + { "AudioClip", new AudioClipHandler() }, + { "AnimationClip", new AnimationClipHandler() }, + { "PreloadData", new PreloadDataHandler() }, + }; + + // serialized files + private AddReference m_AddReferenceCommand = new AddReference(); + private AddAssetBundle m_AddAssetBundleCommand = new AddAssetBundle(); + 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 SqliteConnection m_Database; + private SqliteCommand m_LastId = new SqliteCommand(); + private SqliteTransaction m_CurrentTransaction = null; + public AssetBundleSQLiteWriter(SqliteConnection database, bool skipReferences) + { + m_Database = database; + m_SkipReferences = skipReferences; + } + + public void Init() + { + foreach (var handler in m_Handlers.Values) + { + handler.Init(m_Database); + } + CreateSQLiteCommands(); + } + + private void CreateSQLiteCommands() + { + + // build serialized file commands + m_AddReferenceCommand.CreateCommand(m_Database); + m_AddAssetBundleCommand.CreateCommand(m_Database); + m_AddSerializedFileCommand.CreateCommand(m_Database); + m_AddObjectCommand.CreateCommand(m_Database); + m_AddTypeCommand.CreateCommand(m_Database); + m_InsertDepCommand.CreateCommand(m_Database); + + m_LastId = m_Database.CreateCommand(); + m_LastId.CommandText = "SELECT last_insert_rowid()"; + } + public void BeginAssetBundle(string name, long size) + { + if (m_CurrentAssetBundleId != -1) + { + throw new InvalidOperationException("SQLWriter.BeginAssetBundle called twice"); + } + + m_CurrentAssetBundleId = m_NextAssetBundleId++; + m_AddAssetBundleCommand.SetValue("id", m_CurrentAssetBundleId); + m_AddAssetBundleCommand.SetValue("name", name); + m_AddAssetBundleCommand.SetValue("file_size", size); + m_AddAssetBundleCommand.ExecuteNonQuery(); + } + + public void EndAssetBundle() + { + if (m_CurrentAssetBundleId == -1) + { + throw new InvalidOperationException("SQLWriter.EndAssetBundle called before SQLWriter.BeginAssetBundle"); + } + + m_CurrentAssetBundleId = -1; + } + + public void WriteSerializedFile(string relativePath, string fullPath, string containingFolder) + { + 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()); + int sceneId = -1; + + using var transaction = m_Database.BeginTransaction(); + m_CurrentTransaction = transaction; + + var match = m_RegexSceneFile.Match(relativePath); + + if (match.Success) + { + var sceneName = match.Groups[1].Value; + + // 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)); + + // There are 2 SerializedFiles per Scene, one ends with .sharedAssets. This is a + // dirty trick to avoid inserting the scene object a second time. + if (relativePath.EndsWith(".sharedAssets")) + { + m_AddObjectCommand.SetTransaction(transaction); + m_AddObjectCommand.SetValue("game_object", ""); // or other value + m_AddObjectCommand.SetValue("id", sceneId); + m_AddObjectCommand.SetValue("object_id", 0); + m_AddObjectCommand.SetValue("serialized_file", serializedFileId); + // The type is set to -1 which doesn't exist in Unity, but is associated to + // "Scene" in the database. + m_AddObjectCommand.SetValue("type", -1); + m_AddObjectCommand.SetValue("name", sceneName); + m_AddObjectCommand.SetValue("size", 0); + m_AddObjectCommand.SetValue("crc32", 0); + m_AddObjectCommand.ExecuteNonQuery(); + } + } + + m_LocalToDbFileId.Clear(); + + Context ctx = new() + { + AssetBundleId = m_CurrentAssetBundleId, + SerializedFileId = serializedFileId, + SceneId = sceneId, + ObjectIdProvider = m_ObjectIdProvider, + SerializedFileIdProvider = m_SerializedFileIdProvider, + LocalToDbFileId = m_LocalToDbFileId, + Transaction = transaction, + }; + + ctx.Transaction = transaction; + try + { + m_AddSerializedFileCommand.SetTransaction(transaction); + m_AddSerializedFileCommand.SetValue("id", serializedFileId); + m_AddSerializedFileCommand.SetValue("asset_bundle", m_CurrentAssetBundleId == -1 ? "" : m_CurrentAssetBundleId); + m_AddSerializedFileCommand.SetValue("name", relativePath); + m_AddSerializedFileCommand.ExecuteNonQuery(); + + int localId = 0; + 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())); + } + + foreach (var obj in sf.Objects) + { + var currentObjectId = m_ObjectIdProvider.GetId((serializedFileId, obj.Id)); + // Console.WriteLine($"\nProcessing {currentObjectId}"); + var root = sf.GetTypeTreeRoot(obj.Id); + var offset = obj.Offset; + uint crc32 = 0; + + if (!m_TypeSet.Contains(obj.TypeId)) + { + m_AddTypeCommand.SetTransaction(transaction); + m_AddTypeCommand.SetValue("id", obj.TypeId); + m_AddTypeCommand.SetValue("name", root.Type); + m_AddTypeCommand.ExecuteNonQuery(); + + m_TypeSet.Add(obj.TypeId); + } + + var randomAccessReader = new RandomAccessReader(sf, root, reader, offset); + + string name = string.Empty; + long streamDataSize = 0; + + if (m_Handlers.TryGetValue(root.Type, out var handler)) + { + handler.Process(ctx, currentObjectId, randomAccessReader, + out name, out streamDataSize); + } + else if (randomAccessReader.HasChild("m_Name")) + { + name = randomAccessReader["m_Name"].GetValue(); + } + + if (randomAccessReader.HasChild("m_GameObject")) + { + var pptr = randomAccessReader["m_GameObject"]; + var fileId = m_LocalToDbFileId[pptr["m_FileID"].GetValue()]; + var gameObjectID = m_ObjectIdProvider.GetId((fileId, pptr["m_PathID"].GetValue())); + m_AddObjectCommand.SetValue("game_object", gameObjectID); + } + else + { + m_AddObjectCommand.SetValue("game_object", ""); + } + + if (!m_SkipReferences) + { + crc32 = pptrReader.Process(currentObjectId, offset, root); + } + + // convert this to the new syntax + m_AddObjectCommand.SetTransaction(transaction); + m_AddObjectCommand.SetValue("id", currentObjectId); + m_AddObjectCommand.SetValue("object_id", obj.Id); + m_AddObjectCommand.SetValue("serialized_file", serializedFileId); + m_AddObjectCommand.SetValue("type", obj.TypeId); + m_AddObjectCommand.SetValue("name", name); + m_AddObjectCommand.SetValue("size", obj.Size + streamDataSize); + m_AddObjectCommand.SetValue("crc32", crc32); + m_AddObjectCommand.ExecuteNonQuery(); + + // If this is a Scene AssetBundle, add the object as a depencency of the + // current scene. + if (ctx.SceneId != -1) + { + m_InsertDepCommand.SetTransaction(transaction); + m_InsertDepCommand.SetValue("object", ctx.SceneId); + m_InsertDepCommand.SetValue("dependency", currentObjectId); + m_InsertDepCommand.ExecuteNonQuery(); + } + } + + transaction.Commit(); + } + catch (Exception) + { + transaction.Rollback(); + throw; + } + } + + private int AddReference(long objectId, int fileId, long pathId, string propertyPath, string propertyType) + { + var referencedObjectId = m_ObjectIdProvider.GetId((m_LocalToDbFileId[fileId], pathId)); + m_AddReferenceCommand.SetTransaction(m_CurrentTransaction); + m_AddReferenceCommand.SetValue("object", objectId); + m_AddReferenceCommand.SetValue("referenced_object", referencedObjectId); + m_AddReferenceCommand.SetValue("property_path", propertyPath); + m_AddReferenceCommand.SetValue("property_type", propertyType); + m_AddReferenceCommand.ExecuteNonQuery(); + return referencedObjectId; + } + + public void Dispose() + { + foreach (var handler in m_Handlers.Values) + { + handler.Dispose(); + } + + // Serialized file dispose calls + m_AddAssetBundleCommand.Dispose(); + m_AddSerializedFileCommand.Dispose(); + m_AddReferenceCommand.Dispose(); + m_AddObjectCommand.Dispose(); + m_AddTypeCommand.Dispose(); + m_InsertDepCommand.Dispose(); + + m_LastId.Dispose(); + } +} diff --git a/Analyzer/SQLite/Writers/SQLiteWriter.cs b/Analyzer/SQLite/Writers/SQLiteWriter.cs new file mode 100644 index 0000000..c13699d --- /dev/null +++ b/Analyzer/SQLite/Writers/SQLiteWriter.cs @@ -0,0 +1,67 @@ +using Microsoft.Data.Sqlite; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Analyzer.SQLite.Writers +{ + public class SQLiteWriter : IDisposable + { + private SqliteConnection m_Database; + public SqliteConnection Connection => m_Database; + private string m_DatabaseName; + + + public SQLiteWriter(string databaseName) + { + m_DatabaseName = databaseName; + } + + public void Begin() + { + if (m_Database != null) + { + throw new InvalidOperationException("SQLiteWriter.Begin called twice"); + } + SqliteConnectionStringBuilder builder = new(); + builder.DataSource = m_DatabaseName; + builder.Mode = SqliteOpenMode.ReadWriteCreate; + m_Database = new SqliteConnection(builder.ConnectionString); + File.WriteAllBytes(m_DatabaseName, Array.Empty()); + try + { + m_Database.Open(); + } + catch (Exception e) + { + Console.Error.WriteLine($"Error creating database: {e.Message}"); + } + + // this does all the legacy import of Init.sql + using var command = m_Database.CreateCommand(); + command.CommandText = Resources.Init; + command.ExecuteNonQuery(); + } + + public void End() + { + if (m_Database == null) + { + throw new InvalidOperationException("SQLiteWriter.End called before SQLiteWriter.Begin"); + } + + using var finalizeCommand = m_Database.CreateCommand(); + finalizeCommand.CommandText = Resources.Finalize; + finalizeCommand.ExecuteNonQuery(); + } + + public void Dispose() + { + m_Database?.Dispose(); + m_Database = null; + } + } +} diff --git a/Documentation/addressables-build-reports.md b/Documentation/addressables-build-reports.md new file mode 100644 index 0000000..0b65639 --- /dev/null +++ b/Documentation/addressables-build-reports.md @@ -0,0 +1,147 @@ +# Addressables Build Report Analysis + +## Overview + +Unity Data Tools provides the ability to analyse Unity Addressables build reports. The tool extracts detailed information about bundles, assets, dependencies, file sizes, and build performance metrics. This information can complement extracting information from the Asset Bundles directly. + +When you run the analyzer on a directory containing Addressables build reports, the tool will parse them and add the data to the sqlite database. + +## Database Schema + +The Addressables build data is stored across multiple related tables in the SQLite database: + +## Concepts + +**Builds** - a build corresponds to a content build. This can be part of a player build, or standalone through the Addressables groups window +**Bundles** - asset bundles that are output by the build. +**Groups** - groups in the Addressable Groups window whose settings generate one or more Asset Bundles +**Schemas** - settings for groups that determine how bundles are generated +**Files** - the file in the asset bundle that contains serialized files +**SubFiles** - files that are bundled in the asset bundle, but not stored with the rest of the serialized files (resS, scene sharedAssets) +**Explicit Assets** - these are assets that have had the Addressable checkbox checked in the Editor +**Other Assets** - these are assets that are included because an explicit asset depends upon them + +### Core Tables + +#### `addr_builds` +Main build information table + * id maps to build_id in other tables + +#### `addr_build_groups` +Contains groups used in the build and whether they're pack separate or together. + * guid maps to group_guid in other tables + +#### `addr_build_group_schemas` +Map groups to their schemas + * schema_rid maps to addr_group_schemas.id + * group_id maps to addr_build_groups.id + +#### `addr_build_schemas` +Contain schema names. + * id maps to addr_group_schemas.id + +#### `add_build_schema_data_pairs` +Contains key value pairs of schema settings at time of build. + * schema_id maps to addr_build_schemas.id + +#### `addr_build_bundles` +Bundle-level information including asset counts and file sizes. + +#### `addr_build_bundle_dependent_bundles +Maps bundles to the bundles they depend upon (dependent bundles will be loaded as long as the bundle in question is loaded). + * bundle_id maps to addr_build_bundles.id + * dependent_bundle_rid maps to addr_build_bundles.id + +#### `addr_build_bundle_files` +List files in bundles. These are the serialized files and external files. + * bundle_id maps to addr_build_bundles.id + * file_rid maps to addr_build_files.id + +### `addr_build_explicit_assets` +Explicit assets (marked as Addressable). Has Addressable name and asset information including paths. + * bundle maps to addr_build_bundles.id + * group_guid maps to addr_build_groups.guid + * file maps to addr_build_files.id + +### `addr_build_explicit_asset_internal_referenced_other_assets` +Map explicit assets to other assets they refer to. For instance a prefab to its underlying FBX + * referencing_asset_rid maps to addr_build_explicit_assets.id + * data_from_other_asset_Id maps to addr_build_data_from_other_assets.id + +### `addr_build_data_from_other_assets` +Assets added into the build implicitly by explictly defined assets. + * file maps to addr_build_files.id + +#### `addr_build_cached_bundles` +A view that contains the filename of the built bundle and the name it is stored in the Unity runtime cache. + +### Basic Analysis + +To analyze Addressables build reports in your project: + +```bash +# Analyze all files in a directory (automatically detects Addressables JSON files) +UnityDataTools.exe "Library\com.unity.addressables\BuildReports\" -o "addressables_analysis.db" + +# Include verbose output to see processing details +UnityDataTools.exe "Library\com.unity.addressables\BuildReports\" -o "addressables_analysis.db" --verbose + +# Analyze only JSON files specifically +UnityDataTools.exe "C:\Temp\MyExtractedFiles" -o "addressables_analysis.db" -p "*.json" +``` + +You can analyze a directory with both asset bundles (*.bundle) and json files (*.json) at the same time. + +### Sample Queries + +Once the data is in the database, you can run queries to analyze your Addressables build: + +#### Find the cache name for an addressables bundle +```sql +-- Find cache name for an addressables bundle +SELECT cached_name +FROM addr_build_cached_bundles +WHERE catalog_name = 'packedassets7_assets_all_61d3358060e969d3aad2d9c5c3a7d69b.bundle'; +``` + +#### Bundle Size Analysis +```sql +-- Find largest bundles by file size +SELECT name, file_size, asset_count, compression +FROM addr_build_bundles +ORDER BY file_size DESC +LIMIT 10; +``` + +#### Build Performance Analysis +```sql +-- Analyze build duration and asset counts +SELECT + a.name, + a.duration, + COUNT(b.id) as bundle_count, + SUM(b.asset_count) as total_assets, + SUM(b.file_size) as total_size +FROM addr_builds a +LEFT JOIN addr_build_bundles b ON a.rowid = b.build_id +GROUP BY a.rowid; + +-- Find builds with errors +SELECT name, start_time, duration, error +FROM addr_builds +WHERE error IS NOT NULL AND error != ''; +``` + +#### MonoScript Analysis +```sql +-- Analyze MonoScript distribution across files +SELECT + f.name, + f.mono_script_count, + f.mono_script_size, + b.name as bundle_name +FROM addr_build_files f +JOIN addr_build_bundles b ON f.bundle = b.id AND f.build_id = b.build_id +WHERE f.mono_script_count > 0 +ORDER BY f.mono_script_size DESC; +``` diff --git a/README.md b/README.md index 35b42a8..e6600fa 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ The [command line tool](./UnityDataTool/README.md) runs directly on Unity data f It is designed to scale for large build outputs and has been used to fine-tune big Unity-based games. +The tool also provides comprehensive analysis of **Unity Addressables build reports**, automatically detecting and parsing Addressables JSON build outputs to extract detailed information about bundles, assets, dependencies, file sizes, and build performance metrics. See the [Addressables Build Report Analysis documentation](./Documentation/addressables-build-reports.md) for complete details. + The command line tool uses the UnityFileSystemApi library to access the content of Unity Archives and Serialized files, which are Unity's primary binary formats. This repository also serves as a reference for how this library could be used as part of incorporating functionality into your own tools. ## Repository content