From a289ed33afd4e9c02eb3c1596d74c76cf75e6efd Mon Sep 17 00:00:00 2001 From: Alexander Degtyarev Date: Wed, 5 Feb 2025 17:19:19 +0100 Subject: [PATCH 1/9] Migrating to MSSql for mac-arm64 compatability --- Analyzer.Tests/Analyzer.Tests.csproj | 12 +- Analyzer.Tests/ExpectedDataGenerator.cs | 3 + Analyzer.Tests/SerializedObjectsTests.cs | 3 + Analyzer/Analyzer.csproj | 13 +- Analyzer/AnalyzerTool.cs | 1 - .../SQLite/Handlers/AnimationClipHandler.cs | 27 ++-- .../SQLite/Handlers/AssetBundleHandler.cs | 42 +++--- Analyzer/SQLite/Handlers/AudioClipHandler.cs | 30 ++--- Analyzer/SQLite/Handlers/ISQLiteHandler.cs | 7 +- Analyzer/SQLite/Handlers/MeshHandler.cs | 41 +++--- .../SQLite/Handlers/PreloadDataHandler.cs | 21 ++- Analyzer/SQLite/Handlers/ShaderHandler.cs | 84 ++++++------ Analyzer/SQLite/Handlers/Texture2DHandler.cs | 32 ++--- Analyzer/SQLite/SQLiteWriter.cs | 124 +++++++++++------- ReferenceFinder/ReferenceFinder.csproj | 13 +- ReferenceFinder/ReferenceFinderTool.cs | 22 ++-- TestCommon/Context.cs | 3 +- TestCommon/ExpectedData.cs | 2 + TestCommon/TestCommon.csproj | 11 +- TestCommon/TestFixtures.cs | 2 + TextDumper/TextDumper.csproj | 11 +- UnityDataTool.Tests/ExpectedDataGenerator.cs | 4 +- .../UnityDataTool.Tests.csproj | 12 +- UnityDataTool.Tests/UnityDataToolTests.cs | 8 +- UnityDataTool/UnityDataTool.csproj | 11 +- .../UnityFileSystem.Tests.csproj | 12 +- UnityFileSystem/DllWrapper.cs | 12 +- UnityFileSystem/UnityFileSystem.csproj | 12 +- global.json | 7 + 29 files changed, 347 insertions(+), 235 deletions(-) create mode 100644 global.json diff --git a/Analyzer.Tests/Analyzer.Tests.csproj b/Analyzer.Tests/Analyzer.Tests.csproj index dd740d0..e1ad7f2 100644 --- a/Analyzer.Tests/Analyzer.Tests.csproj +++ b/Analyzer.Tests/Analyzer.Tests.csproj @@ -1,11 +1,21 @@ - net6.0 + net9.0 enable disable false + + latest + + + + AnyCPU + + + + AnyCPU diff --git a/Analyzer.Tests/ExpectedDataGenerator.cs b/Analyzer.Tests/ExpectedDataGenerator.cs index 17b4932..32c008d 100644 --- a/Analyzer.Tests/ExpectedDataGenerator.cs +++ b/Analyzer.Tests/ExpectedDataGenerator.cs @@ -1,3 +1,6 @@ +using System; +using System.IO; +using System.Linq; using UnityDataTools.Analyzer.SerializedObjects; using UnityDataTools.FileSystem; using UnityDataTools.FileSystem.TypeTreeReaders; diff --git a/Analyzer.Tests/SerializedObjectsTests.cs b/Analyzer.Tests/SerializedObjectsTests.cs index 1b58620..647dd75 100644 --- a/Analyzer.Tests/SerializedObjectsTests.cs +++ b/Analyzer.Tests/SerializedObjectsTests.cs @@ -1,3 +1,6 @@ +using System; +using System.IO; +using System.Linq; using NUnit.Framework; using UnityDataTools.FileSystem; using UnityDataTools.FileSystem.TypeTreeReaders; diff --git a/Analyzer/Analyzer.csproj b/Analyzer/Analyzer.csproj index df03d22..d1f3441 100644 --- a/Analyzer/Analyzer.csproj +++ b/Analyzer/Analyzer.csproj @@ -1,11 +1,20 @@ - net6.0 + net9.0 + latest + + + + AnyCPU + + + + AnyCPU - + diff --git a/Analyzer/AnalyzerTool.cs b/Analyzer/AnalyzerTool.cs index 84217be..82d70ba 100644 --- a/Analyzer/AnalyzerTool.cs +++ b/Analyzer/AnalyzerTool.cs @@ -71,7 +71,6 @@ public int Analyze(string path, string databaseName, string searchPattern, bool } catch (Exception e) { - Console.Error.WriteLine(); Console.Error.WriteLine($"Error processing {node.Path} in archive {file}"); } } diff --git a/Analyzer/SQLite/Handlers/AnimationClipHandler.cs b/Analyzer/SQLite/Handlers/AnimationClipHandler.cs index 28d4a7d..d00c60f 100644 --- a/Analyzer/SQLite/Handlers/AnimationClipHandler.cs +++ b/Analyzer/SQLite/Handlers/AnimationClipHandler.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; -using System.Data; -using System.Data.SQLite; +using Microsoft.Data.Sqlite; using UnityDataTools.Analyzer.SerializedObjects; using UnityDataTools.FileSystem.TypeTreeReaders; @@ -9,26 +7,25 @@ namespace UnityDataTools.Analyzer.SQLite.Handlers; public class AnimationClipHandler : ISQLiteHandler { - SQLiteCommand m_InsertCommand; + SqliteCommand m_InsertCommand; - public void Init(SQLiteConnection db) + public void Init(SqliteConnection db) { - using var command = new SQLiteCommand(db); - + using var command = db.CreateCommand(); command.CommandText = Properties.Resources.AnimationClip; command.ExecuteNonQuery(); - - m_InsertCommand = new SQLiteCommand(db); + + m_InsertCommand = db.CreateCommand(); m_InsertCommand.CommandText = "INSERT INTO animation_clips(id, legacy, events) VALUES(@id, @legacy, @events)"; - m_InsertCommand.Parameters.Add("@id", DbType.Int64); - m_InsertCommand.Parameters.Add("@legacy", DbType.Int32); - m_InsertCommand.Parameters.Add("@events", DbType.Int32); + m_InsertCommand.Parameters.Add("@id", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@legacy", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@events", SqliteType.Integer); } public void Process(Context ctx, long objectId, RandomAccessReader reader, out string name, out long streamDataSize) { var animationClip = AnimationClip.Read(reader); - + m_InsertCommand.Transaction = ctx.Transaction; m_InsertCommand.Parameters["@id"].Value = objectId; m_InsertCommand.Parameters["@legacy"].Value = animationClip.Legacy; m_InsertCommand.Parameters["@events"].Value = animationClip.Events; @@ -38,12 +35,12 @@ public void Process(Context ctx, long objectId, RandomAccessReader reader, out s streamDataSize = 0; } - public void Finalize(SQLiteConnection db) + public void Finalize(SqliteConnection db) { } void IDisposable.Dispose() { - m_InsertCommand.Dispose(); + m_InsertCommand?.Dispose(); } } \ No newline at end of file diff --git a/Analyzer/SQLite/Handlers/AssetBundleHandler.cs b/Analyzer/SQLite/Handlers/AssetBundleHandler.cs index 90818b0..80bbc6b 100644 --- a/Analyzer/SQLite/Handlers/AssetBundleHandler.cs +++ b/Analyzer/SQLite/Handlers/AssetBundleHandler.cs @@ -1,7 +1,6 @@ using System; -using System.Data; -using System.Data.SQLite; using System.Text.RegularExpressions; +using Microsoft.Data.Sqlite; using UnityDataTools.Analyzer.SerializedObjects; using UnityDataTools.FileSystem.TypeTreeReaders; @@ -9,26 +8,27 @@ namespace UnityDataTools.Analyzer.SQLite.Handlers; public class AssetBundleHandler : ISQLiteHandler { - SQLiteCommand m_InsertCommand; - private SQLiteCommand m_InsertDepCommand; + SqliteCommand m_InsertCommand; + private SqliteCommand m_InsertDepCommand; private Regex m_SceneNameRegex = new Regex(@"([^//]+)\.unity"); - public void Init(SQLiteConnection db) + public void Init(SqliteConnection db) { - using var command = new SQLiteCommand(db); - + using var command = db.CreateCommand(); command.CommandText = Properties.Resources.AssetBundle; command.ExecuteNonQuery(); - m_InsertCommand = new SQLiteCommand(db); + m_InsertCommand = db.CreateCommand(); + m_InsertCommand.CommandText = "INSERT INTO assets(object, name) VALUES(@object, @name)"; - m_InsertCommand.Parameters.Add("@object", DbType.Int64); - m_InsertCommand.Parameters.Add("@name", DbType.String); + m_InsertCommand.Parameters.Add("@object", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@name", SqliteType.Text); + + m_InsertDepCommand = db.CreateCommand(); - m_InsertDepCommand = new SQLiteCommand(db); m_InsertDepCommand.CommandText = "INSERT INTO asset_dependencies(object, dependency) VALUES(@object, @dependency)"; - m_InsertDepCommand.Parameters.Add("@object", DbType.Int64); - m_InsertDepCommand.Parameters.Add("@dependency", DbType.Int64); + 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) @@ -41,7 +41,7 @@ public void Process(Context ctx, long objectId, RandomAccessReader reader, out s { 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(); @@ -51,7 +51,7 @@ public void Process(Context ctx, long objectId, RandomAccessReader reader, out s 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(); @@ -65,7 +65,7 @@ public void Process(Context ctx, long objectId, RandomAccessReader reader, out s { 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(); @@ -77,10 +77,10 @@ public void Process(Context ctx, long objectId, RandomAccessReader reader, out s streamDataSize = 0; } - public void Finalize(SQLiteConnection db) + public void Finalize(SqliteConnection db) { - using var command = new SQLiteCommand(db); - + using var command = new SqliteCommand(); + command.Connection = db; command.CommandText = "CREATE INDEX asset_dependencies_object ON asset_dependencies(object)"; command.ExecuteNonQuery(); @@ -90,7 +90,7 @@ public void Finalize(SQLiteConnection db) void IDisposable.Dispose() { - m_InsertCommand.Dispose(); - m_InsertDepCommand.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 8428d5d..cfd542e 100644 --- a/Analyzer/SQLite/Handlers/AudioClipHandler.cs +++ b/Analyzer/SQLite/Handlers/AudioClipHandler.cs @@ -1,7 +1,6 @@ using System; -using System.Collections.Generic; +using Microsoft.Data.Sqlite; using System.Data; -using System.Data.SQLite; using UnityDataTools.Analyzer.SerializedObjects; using UnityDataTools.FileSystem.TypeTreeReaders; @@ -9,29 +8,28 @@ namespace UnityDataTools.Analyzer.SQLite.Handlers; public class AudioClipHandler : ISQLiteHandler { - SQLiteCommand m_InsertCommand; + private SqliteCommand m_InsertCommand; - public void Init(SQLiteConnection db) + public void Init(SqliteConnection db) { - using var command = new SQLiteCommand(db); - + using var command = db.CreateCommand(); command.CommandText = Properties.Resources.AudioClip; command.ExecuteNonQuery(); - m_InsertCommand = new SQLiteCommand(db); + m_InsertCommand = db.CreateCommand(); m_InsertCommand.CommandText = "INSERT INTO audio_clips(id, bits_per_sample, frequency, channels, load_type, format) VALUES(@id, @bits_per_sample, @frequency, @channels, @load_type, @format)"; - m_InsertCommand.Parameters.Add("@id", DbType.Int64); - m_InsertCommand.Parameters.Add("@bits_per_sample", DbType.Int32); - m_InsertCommand.Parameters.Add("@frequency", DbType.Int32); - m_InsertCommand.Parameters.Add("@channels", DbType.Int32); - m_InsertCommand.Parameters.Add("@load_type", DbType.Int32); - m_InsertCommand.Parameters.Add("@format", DbType.Int32); + m_InsertCommand.Parameters.Add("@id", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@bits_per_sample", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@frequency", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@channels", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@load_type", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@format", SqliteType.Integer); } public void Process(Context ctx, long objectId, RandomAccessReader reader, out string name, out long streamDataSize) { var audioClip = AudioClip.Read(reader); - + m_InsertCommand.Transaction = ctx.Transaction; m_InsertCommand.Parameters["@id"].Value = objectId; m_InsertCommand.Parameters["@bits_per_sample"].Value = audioClip.BitsPerSample; m_InsertCommand.Parameters["@frequency"].Value = audioClip.Frequency; @@ -45,12 +43,12 @@ public void Process(Context ctx, long objectId, RandomAccessReader reader, out s name = audioClip.Name; } - public void Finalize(SQLiteConnection db) + public void Finalize(SqliteConnection db) { } void IDisposable.Dispose() { - m_InsertCommand.Dispose(); + m_InsertCommand?.Dispose(); } } \ No newline at end of file diff --git a/Analyzer/SQLite/Handlers/ISQLiteHandler.cs b/Analyzer/SQLite/Handlers/ISQLiteHandler.cs index 660762b..ba6dfcf 100644 --- a/Analyzer/SQLite/Handlers/ISQLiteHandler.cs +++ b/Analyzer/SQLite/Handlers/ISQLiteHandler.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using System.Data.SQLite; +using Microsoft.Data.Sqlite; using UnityDataTools.FileSystem.TypeTreeReaders; namespace UnityDataTools.Analyzer.SQLite.Handlers; @@ -13,11 +13,12 @@ public class Context public Util.ObjectIdProvider ObjectIdProvider { get; init; } public Util.IdProvider SerializedFileIdProvider { get; init; } public Dictionary LocalToDbFileId { get; init; } + public SqliteTransaction Transaction { get; set; } } public interface ISQLiteHandler : IDisposable { - void Init(SQLiteConnection db); + void Init(Microsoft.Data.Sqlite.SqliteConnection db); void Process(Context ctx, long objectId, RandomAccessReader reader, out string name, out long streamDataSize); - void Finalize(SQLiteConnection db); + void Finalize(Microsoft.Data.Sqlite.SqliteConnection db); } \ No newline at end of file diff --git a/Analyzer/SQLite/Handlers/MeshHandler.cs b/Analyzer/SQLite/Handlers/MeshHandler.cs index a5c3575..1845b7f 100644 --- a/Analyzer/SQLite/Handlers/MeshHandler.cs +++ b/Analyzer/SQLite/Handlers/MeshHandler.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; -using System.Data; -using System.Data.SQLite; +using Microsoft.Data.Sqlite; using System.Text; using UnityDataTools.Analyzer.SerializedObjects; using UnityDataTools.FileSystem.TypeTreeReaders; @@ -10,33 +8,32 @@ namespace UnityDataTools.Analyzer.SQLite.Handlers; public class MeshHandler : ISQLiteHandler { - SQLiteCommand m_InsertCommand; + SqliteCommand m_InsertCommand; - public void Init(SQLiteConnection db) + public void Init(SqliteConnection db) { - using var command = new SQLiteCommand(db); - + using var command = db.CreateCommand(); command.CommandText = Properties.Resources.Mesh; command.ExecuteNonQuery(); - m_InsertCommand = new SQLiteCommand(db); + m_InsertCommand = db.CreateCommand(); m_InsertCommand.CommandText = "INSERT INTO meshes(id, sub_meshes, blend_shapes, bones, indices, vertices, compression, rw_enabled, vertex_size, channels) VALUES(@id, @sub_meshes, @blend_shapes, @bones, @indices, @vertices, @compression, @rw_enabled, @vertex_size, @channels)"; - m_InsertCommand.Parameters.Add("@id", DbType.Int64); - m_InsertCommand.Parameters.Add("@sub_meshes", DbType.Int32); - m_InsertCommand.Parameters.Add("@blend_shapes", DbType.Int32); - m_InsertCommand.Parameters.Add("@bones", DbType.Int32); - m_InsertCommand.Parameters.Add("@indices", DbType.Int32); - m_InsertCommand.Parameters.Add("@vertices", DbType.Int32); - m_InsertCommand.Parameters.Add("@compression", DbType.Int32); - m_InsertCommand.Parameters.Add("@rw_enabled", DbType.Int32); - m_InsertCommand.Parameters.Add("@vertex_size", DbType.Int32); - m_InsertCommand.Parameters.Add("@channels", DbType.String); + m_InsertCommand.Parameters.Add("@id", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@sub_meshes", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@blend_shapes", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@bones", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@indices", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@vertices", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@compression", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@rw_enabled", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@vertex_size", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@channels", SqliteType.Text); } public void Process(Context ctx, long objectId, RandomAccessReader reader, out string name, out long streamDataSize) { var mesh = Mesh.Read(reader); - + m_InsertCommand.Transaction = ctx.Transaction; m_InsertCommand.Parameters["@id"].Value = objectId; m_InsertCommand.Parameters["@indices"].Value = mesh.Indices; m_InsertCommand.Parameters["@vertices"].Value = mesh.Vertices; @@ -58,7 +55,7 @@ public void Process(Context ctx, long objectId, RandomAccessReader reader, out s channels.AppendLine("]"); } - m_InsertCommand.Parameters["@channels"].Value = channels; + m_InsertCommand.Parameters["@channels"].Value = channels.ToString(); m_InsertCommand.ExecuteNonQuery(); @@ -66,12 +63,12 @@ public void Process(Context ctx, long objectId, RandomAccessReader reader, out s name = mesh.Name; } - public void Finalize(SQLiteConnection db) + public void Finalize(SqliteConnection db) { } void IDisposable.Dispose() { - m_InsertCommand.Dispose(); + m_InsertCommand?.Dispose(); } } \ No newline at end of file diff --git a/Analyzer/SQLite/Handlers/PreloadDataHandler.cs b/Analyzer/SQLite/Handlers/PreloadDataHandler.cs index 7664b61..75f1420 100644 --- a/Analyzer/SQLite/Handlers/PreloadDataHandler.cs +++ b/Analyzer/SQLite/Handlers/PreloadDataHandler.cs @@ -1,6 +1,6 @@ using System; using System.Data; -using System.Data.SQLite; +using Microsoft.Data.Sqlite; using UnityDataTools.Analyzer.SerializedObjects; using UnityDataTools.FileSystem.TypeTreeReaders; @@ -8,22 +8,21 @@ namespace UnityDataTools.Analyzer.SQLite.Handlers; public class PreloadDataHandler : ISQLiteHandler { - SQLiteCommand m_InsertDepCommand; + private SqliteCommand m_InsertDepCommand; - public void Init(SQLiteConnection db) + public void Init(SqliteConnection db) { - using var command = new SQLiteCommand(db); - - m_InsertDepCommand = new SQLiteCommand(db); + m_InsertDepCommand = db.CreateCommand(); + m_InsertDepCommand.Connection = db; m_InsertDepCommand.CommandText = "INSERT INTO asset_dependencies(object, dependency) VALUES(@object, @dependency)"; - m_InsertDepCommand.Parameters.Add("@object", DbType.Int64); - m_InsertDepCommand.Parameters.Add("@dependency", DbType.Int64); + 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 preloadData = PreloadData.Read(reader); - + m_InsertDepCommand.Transaction = ctx.Transaction; m_InsertDepCommand.Parameters["@object"].Value = ctx.SceneId; foreach (var asset in preloadData.Assets) @@ -39,12 +38,12 @@ public void Process(Context ctx, long objectId, RandomAccessReader reader, out s streamDataSize = 0; } - public void Finalize(SQLiteConnection db) + public void Finalize(SqliteConnection db) { } void IDisposable.Dispose() { - m_InsertDepCommand.Dispose(); + m_InsertDepCommand?.Dispose(); } } \ No newline at end of file diff --git a/Analyzer/SQLite/Handlers/ShaderHandler.cs b/Analyzer/SQLite/Handlers/ShaderHandler.cs index c4394ef..6731aad 100644 --- a/Analyzer/SQLite/Handlers/ShaderHandler.cs +++ b/Analyzer/SQLite/Handlers/ShaderHandler.cs @@ -1,58 +1,56 @@ using System; using System.Collections.Generic; -using System.Data; -using System.Data.SQLite; +using Microsoft.Data.Sqlite; using UnityDataTools.FileSystem.TypeTreeReaders; namespace UnityDataTools.Analyzer.SQLite.Handlers; public class ShaderHandler : ISQLiteHandler { - SQLiteCommand m_InsertCommand; - SQLiteCommand m_InsertSubProgramCommand; - SQLiteCommand m_InsertKeywordCommand; - SQLiteCommand m_InsertSubProgramKeywordsCommand; + private SqliteCommand m_InsertCommand; + private SqliteCommand m_InsertSubProgramCommand; + private SqliteCommand m_InsertKeywordCommand; + private SqliteCommand m_InsertSubProgramKeywordsCommand; static long s_SubProgramId = 0; static Dictionary s_GlobalKeywords = new(); - public void Init(SQLiteConnection db) + public void Init(SqliteConnection db) { s_SubProgramId = 0; s_GlobalKeywords.Clear(); - using var command = new SQLiteCommand(db); - + using var command = db.CreateCommand(); command.CommandText = Properties.Resources.Shader; command.ExecuteNonQuery(); - m_InsertCommand = new SQLiteCommand(db); + m_InsertCommand = db.CreateCommand(); m_InsertCommand.CommandText = "INSERT INTO shaders(id, decompressed_size, unique_programs) VALUES(@id, @decompressed_size, @unique_programs)"; - m_InsertCommand.Parameters.Add("@id", DbType.Int64); - m_InsertCommand.Parameters.Add("@decompressed_size", DbType.Int32); - m_InsertCommand.Parameters.Add("@unique_programs", DbType.Int32); + m_InsertCommand.Parameters.Add("@id", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@decompressed_size", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@unique_programs", SqliteType.Integer); - m_InsertSubProgramCommand = new SQLiteCommand(db); + m_InsertSubProgramCommand = db.CreateCommand(); m_InsertSubProgramCommand.CommandText = "INSERT INTO shader_subprograms(id, shader, sub_shader, pass, pass_name, sub_program, hw_tier, shader_type, api) VALUES(@id, @shader, @sub_shader, @pass, @pass_name, @sub_program, @hw_tier, @shader_type, @api)"; - m_InsertSubProgramCommand.Parameters.Add("@id", DbType.Int64); - m_InsertSubProgramCommand.Parameters.Add("@shader", DbType.Int64); - m_InsertSubProgramCommand.Parameters.Add("@sub_shader", DbType.Int32); - m_InsertSubProgramCommand.Parameters.Add("@pass", DbType.Int32); - m_InsertSubProgramCommand.Parameters.Add("@pass_name", DbType.String); - m_InsertSubProgramCommand.Parameters.Add("@sub_program", DbType.Int32); - m_InsertSubProgramCommand.Parameters.Add("@hw_tier", DbType.Int32); - m_InsertSubProgramCommand.Parameters.Add("@shader_type", DbType.String); - m_InsertSubProgramCommand.Parameters.Add("@api", DbType.Int32); - - m_InsertKeywordCommand = new SQLiteCommand(db); + m_InsertSubProgramCommand.Parameters.Add("@id", SqliteType.Integer); + m_InsertSubProgramCommand.Parameters.Add("@shader", SqliteType.Integer); + m_InsertSubProgramCommand.Parameters.Add("@sub_shader", SqliteType.Integer); + m_InsertSubProgramCommand.Parameters.Add("@pass", SqliteType.Integer); + m_InsertSubProgramCommand.Parameters.Add("@pass_name", SqliteType.Text); + m_InsertSubProgramCommand.Parameters.Add("@sub_program", SqliteType.Integer); + m_InsertSubProgramCommand.Parameters.Add("@hw_tier", SqliteType.Integer); + m_InsertSubProgramCommand.Parameters.Add("@shader_type", SqliteType.Text); + m_InsertSubProgramCommand.Parameters.Add("@api", SqliteType.Integer); + + m_InsertKeywordCommand = db.CreateCommand(); m_InsertKeywordCommand.CommandText = "INSERT INTO shader_keywords(id, keyword) VALUES(@id, @keyword)"; - m_InsertKeywordCommand.Parameters.Add("@id", DbType.Int32); - m_InsertKeywordCommand.Parameters.Add("@keyword", DbType.String); + m_InsertKeywordCommand.Parameters.Add("@id", SqliteType.Integer); + m_InsertKeywordCommand.Parameters.Add("@keyword", SqliteType.Text); - m_InsertSubProgramKeywordsCommand = new SQLiteCommand(db); + m_InsertSubProgramKeywordsCommand = db.CreateCommand(); m_InsertSubProgramKeywordsCommand.CommandText = "INSERT INTO shader_subprogram_keywords(subprogram_id, keyword_id) VALUES (@subprogram_id, @keyword_id)"; - m_InsertSubProgramKeywordsCommand.Parameters.Add("@subprogram_id", DbType.Int64); - m_InsertSubProgramKeywordsCommand.Parameters.Add("@keyword_id", DbType.Int32); + m_InsertSubProgramKeywordsCommand.Parameters.Add("@subprogram_id", SqliteType.Integer); + m_InsertSubProgramKeywordsCommand.Parameters.Add("@keyword_id", SqliteType.Integer); } public void Process(Context ctx, long objectId, RandomAccessReader reader, out string name, out long streamDataSize) @@ -64,10 +62,11 @@ public void Process(Context ctx, long objectId, RandomAccessReader reader, out s for (int i = 0; i < shader.Keywords.Count; ++i) { var keyword = shader.Keywords[i]; - var id = GetKeywordId(keyword); + var id = GetKeywordId(keyword,ctx.Transaction); localToGlobalKeywords[i] = id; } + m_InsertCommand.Transaction = ctx.Transaction; m_InsertCommand.Parameters["@id"].Value = objectId; for (int subShaderIndex = 0; subShaderIndex < shader.SubShaders.Count; ++subShaderIndex) @@ -79,7 +78,7 @@ public void Process(Context ctx, long objectId, RandomAccessReader reader, out s for (int passIndex = 0; passIndex < subShader.Passes.Count; ++passIndex) { var pass = subShader.Passes[passIndex]; - + m_InsertSubProgramCommand.Transaction = ctx.Transaction; m_InsertSubProgramCommand.Parameters["@shader"].Value = objectId; m_InsertSubProgramCommand.Parameters["@pass"].Value = passIndex; m_InsertSubProgramCommand.Parameters["@pass_name"].Value = pass.Name; @@ -102,7 +101,8 @@ public void Process(Context ctx, long objectId, RandomAccessReader reader, out s m_InsertSubProgramCommand.Parameters["@hw_tier"].Value = program.HwTier; m_InsertSubProgramCommand.Parameters["@api"].Value = program.Api; m_InsertSubProgramCommand.ExecuteNonQuery(); - + + m_InsertSubProgramKeywordsCommand.Transaction = ctx.Transaction; m_InsertSubProgramKeywordsCommand.Parameters["@subprogram_id"].Value = s_SubProgramId; foreach (var keyword in program.Keywords) { @@ -126,7 +126,7 @@ public void Process(Context ctx, long objectId, RandomAccessReader reader, out s streamDataSize = 0; } - private int GetKeywordId(string keyword) + private int GetKeywordId(string keyword, SqliteTransaction ctxTransaction) { int id; @@ -134,7 +134,7 @@ private int GetKeywordId(string keyword) { id = s_GlobalKeywords.Count; s_GlobalKeywords[keyword] = id; - + m_InsertKeywordCommand.Transaction = ctxTransaction; m_InsertKeywordCommand.Parameters["@id"].Value = id; m_InsertKeywordCommand.Parameters["@keyword"].Value = keyword; m_InsertKeywordCommand.ExecuteNonQuery(); @@ -143,10 +143,10 @@ private int GetKeywordId(string keyword) return id; } - public void Finalize(SQLiteConnection db) + public void Finalize(SqliteConnection db) { - using var command = new SQLiteCommand(db); - + using var command = new SqliteCommand(); + command.Connection = db; command.CommandText = "CREATE INDEX shader_subprograms_shader_index ON shader_subprograms(shader)"; command.ExecuteNonQuery(); @@ -156,9 +156,9 @@ public void Finalize(SQLiteConnection db) void IDisposable.Dispose() { - m_InsertCommand.Dispose(); - m_InsertSubProgramCommand.Dispose(); - m_InsertKeywordCommand.Dispose(); - m_InsertSubProgramKeywordsCommand.Dispose(); + m_InsertCommand?.Dispose(); + m_InsertSubProgramCommand?.Dispose(); + m_InsertKeywordCommand?.Dispose(); + m_InsertSubProgramKeywordsCommand?.Dispose(); } } \ No newline at end of file diff --git a/Analyzer/SQLite/Handlers/Texture2DHandler.cs b/Analyzer/SQLite/Handlers/Texture2DHandler.cs index dfa9103..fe26f1a 100644 --- a/Analyzer/SQLite/Handlers/Texture2DHandler.cs +++ b/Analyzer/SQLite/Handlers/Texture2DHandler.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; -using System.Data; -using System.Data.SQLite; +using Microsoft.Data.Sqlite; using UnityDataTools.Analyzer.SerializedObjects; using UnityDataTools.FileSystem.TypeTreeReaders; @@ -9,48 +7,46 @@ namespace UnityDataTools.Analyzer.SQLite.Handlers; public class Texture2DHandler : ISQLiteHandler { - SQLiteCommand m_InsertCommand; + SqliteCommand m_InsertCommand = new SqliteCommand(); - public void Init(SQLiteConnection db) + public void Init(SqliteConnection db) { - using var command = new SQLiteCommand(db); - + using var command = db.CreateCommand(); command.CommandText = Properties.Resources.Texture2D; command.ExecuteNonQuery(); - m_InsertCommand = new SQLiteCommand(db); + m_InsertCommand = db.CreateCommand(); m_InsertCommand.CommandText = "INSERT INTO textures(id, width, height, format, rw_enabled, mip_count) VALUES(@id, @width, @height, @format, @rw_enabled, @mip_count)"; - m_InsertCommand.Parameters.Add("@id", DbType.Int64); - m_InsertCommand.Parameters.Add("@width", DbType.Int32); - m_InsertCommand.Parameters.Add("@height", DbType.Int32); - m_InsertCommand.Parameters.Add("@format", DbType.Int32); - m_InsertCommand.Parameters.Add("@rw_enabled", DbType.Int32); - m_InsertCommand.Parameters.Add("@mip_count", DbType.Int32); + m_InsertCommand.Parameters.Add("@id", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@width", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@height", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@format", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@rw_enabled", SqliteType.Integer); + m_InsertCommand.Parameters.Add("@mip_count", SqliteType.Integer); } public void Process(Context ctx, long objectId, RandomAccessReader reader, out string name, out long streamDataSize) { var texture2d = Texture2D.Read(reader); - + m_InsertCommand.Transaction = ctx.Transaction; m_InsertCommand.Parameters["@id"].Value = objectId; m_InsertCommand.Parameters["@width"].Value = texture2d.Width; m_InsertCommand.Parameters["@height"].Value = texture2d.Height; m_InsertCommand.Parameters["@format"].Value = texture2d.Format; m_InsertCommand.Parameters["@rw_enabled"].Value = texture2d.RwEnabled; m_InsertCommand.Parameters["@mip_count"].Value = texture2d.MipCount; - m_InsertCommand.ExecuteNonQuery(); name = texture2d.Name; streamDataSize = texture2d.StreamDataSize; } - public void Finalize(SQLiteConnection db) + public void Finalize(SqliteConnection db) { } void IDisposable.Dispose() { - m_InsertCommand.Dispose(); + m_InsertCommand?.Dispose(); } } \ No newline at end of file diff --git a/Analyzer/SQLite/SQLiteWriter.cs b/Analyzer/SQLite/SQLiteWriter.cs index b65b3bc..5ce37db 100644 --- a/Analyzer/SQLite/SQLiteWriter.cs +++ b/Analyzer/SQLite/SQLiteWriter.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; using System.Data; -using System.Data.SQLite; -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics; +using Microsoft.Data.Sqlite; using System.IO; using System.Text.RegularExpressions; -using UnityDataTools.Analyzer.SerializedObjects; using UnityDataTools.Analyzer.SQLite.Handlers; using UnityDataTools.FileSystem; using UnityDataTools.FileSystem.TypeTreeReaders; @@ -40,15 +39,15 @@ public class SQLiteWriter : IWriter { "AssetBundle", new AssetBundleHandler() }, { "PreloadData", new PreloadDataHandler() }, }; - - private SQLiteConnection m_Database; - private SQLiteCommand m_AddReferenceCommand; - private SQLiteCommand m_AddAssetBundleCommand; - private SQLiteCommand m_AddSerializedFileCommand; - private SQLiteCommand m_AddObjectCommand; - private SQLiteCommand m_AddTypeCommand; - private SQLiteCommand m_InsertDepCommand; - + + 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; @@ -61,11 +60,19 @@ public void Begin() { throw new InvalidOperationException("SQLiteWriter.Begin called twice"); } - - m_Database = new SQLiteConnection($"Data Source={m_DatabaseName};Version=3;New=True;Foreign Keys=False;"); - - SQLiteConnection.CreateFile(m_DatabaseName); - m_Database.Open(); + 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; @@ -73,7 +80,11 @@ public void Begin() 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(); @@ -100,43 +111,43 @@ 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", DbType.Int32); - m_AddAssetBundleCommand.Parameters.Add("@name", DbType.String); - m_AddAssetBundleCommand.Parameters.Add("@file_size", DbType.Int64); + 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", DbType.Int32); - m_AddSerializedFileCommand.Parameters.Add("@asset_bundle", DbType.Int32); - m_AddSerializedFileCommand.Parameters.Add("@name", DbType.String); + 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", DbType.Int64); - m_AddReferenceCommand.Parameters.Add("@referenced_object", DbType.Int64); - m_AddReferenceCommand.Parameters.Add("@property_path", DbType.String); - m_AddReferenceCommand.Parameters.Add("@property_type", DbType.String); + 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", DbType.Int64); - m_AddObjectCommand.Parameters.Add("@object_id", DbType.Int64); - m_AddObjectCommand.Parameters.Add("@serialized_file", DbType.Int32); - m_AddObjectCommand.Parameters.Add("@type", DbType.Int32); - m_AddObjectCommand.Parameters.Add("@name", DbType.String); - m_AddObjectCommand.Parameters.Add("@game_object", DbType.Int64); - m_AddObjectCommand.Parameters.Add("@size", DbType.Int64); - m_AddObjectCommand.Parameters.Add("@crc32", DbType.UInt32); + 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", DbType.Int32); - m_AddTypeCommand.Parameters.Add("@name", DbType.String); + 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", DbType.Int64); - m_InsertDepCommand.Parameters.Add("@dependency", DbType.Int64); + m_InsertDepCommand.Parameters.Add("@object", SqliteType.Integer); + m_InsertDepCommand.Parameters.Add("@dependency", SqliteType.Integer); } public void BeginAssetBundle(string name, long size) @@ -212,11 +223,13 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con }; using var transaction = m_Database.BeginTransaction(); - + m_CurrentTransaction = transaction; + ctx.Transaction = transaction; try { + m_AddSerializedFileCommand.Transaction = transaction; m_AddSerializedFileCommand.Parameters["@id"].Value = serializedFileId; - m_AddSerializedFileCommand.Parameters["@asset_bundle"].Value = m_CurrentAssetBundleId == -1 ? null : m_CurrentAssetBundleId; + m_AddSerializedFileCommand.Parameters["@asset_bundle"].Value = m_CurrentAssetBundleId == -1 ? "" : m_CurrentAssetBundleId; m_AddSerializedFileCommand.Parameters["@name"].Value = relativePath; m_AddSerializedFileCommand.ExecuteNonQuery(); @@ -231,13 +244,14 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con 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(); @@ -247,7 +261,7 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con var randomAccessReader = new RandomAccessReader(sf, root, reader, offset); - string name = null; + string name = string.Empty; long streamDataSize = 0; if (m_Handlers.TryGetValue(root.Type, out var handler)) @@ -259,22 +273,30 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con { name = randomAccessReader["m_Name"].GetValue(); } - + if (randomAccessReader.HasChild("m_GameObject")) { var pptr = randomAccessReader["m_GameObject"]; var fileId = m_LocalToDbFileId[pptr["m_FileID"].GetValue()]; - m_AddObjectCommand.Parameters["@game_object"].Value = - m_ObjectIdProvider.GetId((fileId, pptr["m_PathID"].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 = null; + m_AddObjectCommand.Parameters["@game_object"].Value = ""; } if (!m_SkipReferences) { - crc32 = pptrReader.Process(currentObjectId, offset, root); + try + { + crc32 = pptrReader.Process(currentObjectId, offset, root); + } + catch (Exception e) + { + Console.Error.WriteLine(e); + throw e; + } } m_AddObjectCommand.Parameters["@id"].Value = currentObjectId; @@ -284,6 +306,7 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con 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 @@ -292,14 +315,16 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con { m_InsertDepCommand.Parameters["@object"].Value = ctx.SceneId; m_InsertDepCommand.Parameters["@dependency"].Value = currentObjectId; + m_InsertDepCommand.Transaction = transaction; m_InsertDepCommand.ExecuteNonQuery(); } } transaction.Commit(); } - catch (Exception) + catch (Exception e) { + Console.Error.WriteLine($"Error processing {serializedFileId} error: {e.Message}"); transaction.Rollback(); throw; } @@ -308,6 +333,7 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con 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; diff --git a/ReferenceFinder/ReferenceFinder.csproj b/ReferenceFinder/ReferenceFinder.csproj index 99a08e3..0e844a5 100644 --- a/ReferenceFinder/ReferenceFinder.csproj +++ b/ReferenceFinder/ReferenceFinder.csproj @@ -2,13 +2,22 @@ Library - net6.0 + net9.0 + latest + + + + AnyCPU + + + + AnyCPU - + diff --git a/ReferenceFinder/ReferenceFinderTool.cs b/ReferenceFinder/ReferenceFinderTool.cs index 4f7bbb4..8569f13 100644 --- a/ReferenceFinder/ReferenceFinderTool.cs +++ b/ReferenceFinder/ReferenceFinderTool.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Data; -using System.Data.SQLite; +using Microsoft.Data.Sqlite; using System.IO; namespace UnityDataTools.ReferenceFinder; @@ -19,8 +19,8 @@ public ReferenceTreeNode(long id) public class ReferenceFinderTool { - SQLiteCommand m_GetRefsCommand; - SQLiteCommand m_GetObjectCommand; + SqliteCommand m_GetRefsCommand; + SqliteCommand m_GetObjectCommand; List m_Roots = new List(); HashSet<(long, string)> m_ProcessedObjects = new HashSet<(long, string)>(); @@ -29,11 +29,11 @@ public class ReferenceFinderTool public int FindReferences(string objectName, string objectType, string databasePath, string outputFile, bool findAll) { var objectIds = new List(); - SQLiteConnection db; + SqliteConnection db; try { - db = new SQLiteConnection($"Data Source={databasePath};Version=3;Foreign Keys=False;"); + db = new SqliteConnection($"Data Source={databasePath};Version=3;Foreign Keys=False;"); db.Open(); } catch (Exception e) @@ -51,7 +51,7 @@ public int FindReferences(string objectName, string objectType, string databaseP return 1; } - SQLiteCommand getObjectIds; + SqliteCommand getObjectIds; if (objectType != null && objectType != "") { @@ -87,11 +87,11 @@ public int FindReferences(string objectName, string objectType, string databaseP public int FindReferences(long objectId, string databasePath, string outputFile, bool findAll) { var objectIds = new List(); - SQLiteConnection db; + SqliteConnection db; try { - db = new SQLiteConnection($"Data Source={databasePath};Version=3;Foreign Keys=False;"); + db = new SqliteConnection($"Data Source={databasePath};Version=3;Foreign Keys=False;"); db.Open(); } catch (Exception e) @@ -105,13 +105,13 @@ public int FindReferences(long objectId, string databasePath, string outputFile, return FindReferences(db, outputFile, objectIds, findAll); } - int FindReferences(SQLiteConnection db, string outputFile, IList objectIds, bool findAll) + int FindReferences(SqliteConnection db, string outputFile, IList objectIds, bool findAll) { m_Writer = new StreamWriter(outputFile); m_GetRefsCommand = db.CreateCommand(); m_GetRefsCommand.CommandText = @"SELECT object, property_path, EXISTS (SELECT * FROM assets a WHERE a.object = r.object) FROM refs r WHERE referenced_object = @id"; - m_GetRefsCommand.Parameters.Add("@id", DbType.Int64); + m_GetRefsCommand.Parameters.Add("@id", SqliteType.Integer); m_GetObjectCommand = db.CreateCommand(); m_GetObjectCommand.CommandText = @@ -129,7 +129,7 @@ LEFT JOIN refs r '') script FROM object_view o WHERE o.id = @id"; - m_GetObjectCommand.Parameters.Add("@id", DbType.Int64); + m_GetObjectCommand.Parameters.Add("@id", SqliteType.Integer); for (int i = 0; i < objectIds.Count; ++i) { diff --git a/TestCommon/Context.cs b/TestCommon/Context.cs index 2f40652..3450e2f 100644 --- a/TestCommon/Context.cs +++ b/TestCommon/Context.cs @@ -1,4 +1,5 @@ -using NUnit.Framework; +using System.IO; +using NUnit.Framework; namespace UnityDataTools.TestCommon; diff --git a/TestCommon/ExpectedData.cs b/TestCommon/ExpectedData.cs index 89701b2..fcfd93f 100644 --- a/TestCommon/ExpectedData.cs +++ b/TestCommon/ExpectedData.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; +using System.IO; using Newtonsoft.Json; namespace UnityDataTools.TestCommon; diff --git a/TestCommon/TestCommon.csproj b/TestCommon/TestCommon.csproj index 3177c02..9791494 100644 --- a/TestCommon/TestCommon.csproj +++ b/TestCommon/TestCommon.csproj @@ -1,10 +1,19 @@ - net6.0 + net9.0 enable disable TestCommon + latest + + + + AnyCPU + + + + AnyCPU diff --git a/TestCommon/TestFixtures.cs b/TestCommon/TestFixtures.cs index 1e0c351..b9c0c17 100644 --- a/TestCommon/TestFixtures.cs +++ b/TestCommon/TestFixtures.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; +using System.IO; using NUnit.Framework; namespace UnityDataTools.TestCommon; diff --git a/TextDumper/TextDumper.csproj b/TextDumper/TextDumper.csproj index 9bce643..1e54dd1 100644 --- a/TextDumper/TextDumper.csproj +++ b/TextDumper/TextDumper.csproj @@ -2,9 +2,18 @@ Library - net6.0 + net9.0 + latest + + + + AnyCPU + + + + AnyCPU diff --git a/UnityDataTool.Tests/ExpectedDataGenerator.cs b/UnityDataTool.Tests/ExpectedDataGenerator.cs index 6853daf..46323bb 100644 --- a/UnityDataTool.Tests/ExpectedDataGenerator.cs +++ b/UnityDataTool.Tests/ExpectedDataGenerator.cs @@ -1,4 +1,4 @@ -using System.Data.SQLite; +using Microsoft.Data.Sqlite; using System.IO; using UnityDataTools.FileSystem; using UnityDataTools.TestCommon; @@ -26,7 +26,7 @@ public static void Generate(Context context) Program.Main(new string[] { "analyze", Path.Combine(context.UnityDataFolder), "-r" }); - using var db = new SQLiteConnection($"Data Source={Path.Combine(Directory.GetCurrentDirectory(), "database.db")};Version=3;New=True;Foreign Keys=False;"); + using var db = new SqliteConnection($"Data Source={Path.Combine(Directory.GetCurrentDirectory(), "database.db")};Version=3;New=True;Foreign Keys=False;"); db.Open(); using (var cmd = db.CreateCommand()) diff --git a/UnityDataTool.Tests/UnityDataTool.Tests.csproj b/UnityDataTool.Tests/UnityDataTool.Tests.csproj index 974c0aa..b96890e 100644 --- a/UnityDataTool.Tests/UnityDataTool.Tests.csproj +++ b/UnityDataTool.Tests/UnityDataTool.Tests.csproj @@ -1,9 +1,19 @@  - net6.0 + net9.0 false + + latest + + + + AnyCPU + + + + AnyCPU diff --git a/UnityDataTool.Tests/UnityDataToolTests.cs b/UnityDataTool.Tests/UnityDataToolTests.cs index b501a68..3127af1 100644 --- a/UnityDataTool.Tests/UnityDataToolTests.cs +++ b/UnityDataTool.Tests/UnityDataToolTests.cs @@ -1,5 +1,5 @@ using System; -using System.Data.SQLite; +using Microsoft.Data.Sqlite; using System.IO; using System.Linq; using System.Text.RegularExpressions; @@ -269,7 +269,7 @@ public async Task Analyze_WithPatternNoMatch_DatabaseEmpty( Assert.AreEqual(0, await Program.Main(new string[] { "analyze", analyzePath }.Concat(options.Split(" ")).ToArray())); - using var db = new SQLiteConnection($"Data Source={databasePath};Version=3;New=True;Foreign Keys=False;"); + using var db = new SqliteConnection($"Data Source={databasePath};Version=3;New=True;Foreign Keys=False;"); db.Open(); using (var cmd = db.CreateCommand()) @@ -294,7 +294,7 @@ public async Task Analyze_WithOutputFile_DatabaseCorrect( private void ValidateDatabase(string databasePath, bool withRefs) { - using var db = new SQLiteConnection($"Data Source={databasePath};Version=3;New=True;Foreign Keys=False;"); + using var db = new SqliteConnection($"Data Source={databasePath};Version=3;New=True;Foreign Keys=False;"); db.Open(); using (var cmd = db.CreateCommand()) @@ -371,7 +371,7 @@ public async Task Analyze_PlayerData_DatabaseCorrect() Assert.AreEqual(0, await Program.Main(new string[] { "analyze", analyzePath, "-p", "*." })); - using var db = new SQLiteConnection($"Data Source={databasePath};Version=3;New=True;Foreign Keys=False;"); + using var db = new SqliteConnection($"Data Source={databasePath};Version=3;New=True;Foreign Keys=False;"); db.Open(); using var cmd = db.CreateCommand(); diff --git a/UnityDataTool/UnityDataTool.csproj b/UnityDataTool/UnityDataTool.csproj index 2e7ee59..afb59d1 100644 --- a/UnityDataTool/UnityDataTool.csproj +++ b/UnityDataTool/UnityDataTool.csproj @@ -2,7 +2,16 @@ Exe - net6.0 + net9.0 + latest + + + + AnyCPU + + + + AnyCPU diff --git a/UnityFileSystem.Tests/UnityFileSystem.Tests.csproj b/UnityFileSystem.Tests/UnityFileSystem.Tests.csproj index 8be00a7..074bc9c 100644 --- a/UnityFileSystem.Tests/UnityFileSystem.Tests.csproj +++ b/UnityFileSystem.Tests/UnityFileSystem.Tests.csproj @@ -1,11 +1,17 @@  - net6.0 - + net9.0 false + latest + + + + AnyCPU + - AnyCPU;x86 + + AnyCPU diff --git a/UnityFileSystem/DllWrapper.cs b/UnityFileSystem/DllWrapper.cs index 14b7888..ea16660 100644 --- a/UnityFileSystem/DllWrapper.cs +++ b/UnityFileSystem/DllWrapper.cs @@ -4,7 +4,7 @@ namespace UnityDataTools.FileSystem; -internal class UnityArchiveHandle : SafeHandle +public class UnityArchiveHandle : SafeHandle { public UnityArchiveHandle() : base(IntPtr.Zero, true) { @@ -18,7 +18,7 @@ protected override bool ReleaseHandle() } } -internal class UnityFileHandle : SafeHandle +public class UnityFileHandle : SafeHandle { public UnityFileHandle() : base(IntPtr.Zero, true) { @@ -32,7 +32,7 @@ protected override bool ReleaseHandle() } } -internal class SerializedFileHandle : SafeHandle +public class SerializedFileHandle : SafeHandle { public SerializedFileHandle() : base(IntPtr.Zero, true) { @@ -46,7 +46,7 @@ protected override bool ReleaseHandle() } } -internal class TypeTreeHandle : SafeHandle +public class TypeTreeHandle : SafeHandle { public TypeTreeHandle() : base(IntPtr.Zero, true) { @@ -62,7 +62,7 @@ protected override bool ReleaseHandle() internal IntPtr Handle => handle; } -internal enum ReturnCode +public enum ReturnCode { Success, AlreadyInitialized, @@ -138,7 +138,7 @@ public enum TypeTreeMetaFlags AnyChildUsesAlignBytes = 1 << 15, } -internal static class DllWrapper +public static class DllWrapper { [DllImport("UnityFileSystemApi", CallingConvention = CallingConvention.Cdecl, diff --git a/UnityFileSystem/UnityFileSystem.csproj b/UnityFileSystem/UnityFileSystem.csproj index cef3abc..7267f5a 100644 --- a/UnityFileSystem/UnityFileSystem.csproj +++ b/UnityFileSystem/UnityFileSystem.csproj @@ -1,7 +1,17 @@  - net6.0 + net9.0 + e934fe3f-4c03-4bed-8f71-e6213d731c9e + latest + + + + AnyCPU + + + + AnyCPU diff --git a/global.json b/global.json new file mode 100644 index 0000000..f4fd385 --- /dev/null +++ b/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "9.0.0", + "rollForward": "latestMajor", + "allowPrerelease": true + } +} \ No newline at end of file From b03a5e065d2adeabbedb85e5252c6d6e1ce47786 Mon Sep 17 00:00:00 2001 From: Alexander Degtyarev Date: Tue, 11 Feb 2025 11:42:12 +0100 Subject: [PATCH 2/9] rethrow and up filesystemapi to 6.1 --- Analyzer/SQLite/SQLiteWriter.cs | 4 +--- UnityFileSystem/UnityFileSystemApi.dylib | Bin 585568 -> 638469 bytes 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Analyzer/SQLite/SQLiteWriter.cs b/Analyzer/SQLite/SQLiteWriter.cs index 5ce37db..fa64d6c 100644 --- a/Analyzer/SQLite/SQLiteWriter.cs +++ b/Analyzer/SQLite/SQLiteWriter.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Data; -using System.Diagnostics; using Microsoft.Data.Sqlite; using System.IO; using System.Text.RegularExpressions; @@ -295,7 +293,7 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con catch (Exception e) { Console.Error.WriteLine(e); - throw e; + throw; } } diff --git a/UnityFileSystem/UnityFileSystemApi.dylib b/UnityFileSystem/UnityFileSystemApi.dylib index d4ed846e241a53e22670344cd167fa4f2bf59553..a8b2e21d8dcb20b6fa89baa1a5d74398b113e5b5 100755 GIT binary patch literal 638469 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 Ny7Y(1Ok`$9{~r(?GVcHY From 61f9287c996a5c37f14bf35d4072f3f0aec63f0b Mon Sep 17 00:00:00 2001 From: Alexander Degtyarev Date: Tue, 11 Feb 2025 12:21:51 +0100 Subject: [PATCH 3/9] bump mssqlite ver to 9.0.1 --- Analyzer/Analyzer.csproj | 2 +- ReferenceFinder/ReferenceFinder.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Analyzer/Analyzer.csproj b/Analyzer/Analyzer.csproj index d1f3441..ac217d0 100644 --- a/Analyzer/Analyzer.csproj +++ b/Analyzer/Analyzer.csproj @@ -14,7 +14,7 @@ - + diff --git a/ReferenceFinder/ReferenceFinder.csproj b/ReferenceFinder/ReferenceFinder.csproj index 0e844a5..1762447 100644 --- a/ReferenceFinder/ReferenceFinder.csproj +++ b/ReferenceFinder/ReferenceFinder.csproj @@ -17,7 +17,7 @@ - + From b3c082edc4ccd41c8a1f105e97aa9c55373c8669 Mon Sep 17 00:00:00 2001 From: jacob-kjaer Date: Tue, 11 Feb 2025 13:33:44 +0100 Subject: [PATCH 4/9] test: Fix connection strings and teardowns --- UnityDataTool.Tests/UnityDataToolTests.cs | 31 ++++++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/UnityDataTool.Tests/UnityDataToolTests.cs b/UnityDataTool.Tests/UnityDataToolTests.cs index 3127af1..6b5799f 100644 --- a/UnityDataTool.Tests/UnityDataToolTests.cs +++ b/UnityDataTool.Tests/UnityDataToolTests.cs @@ -37,6 +37,8 @@ public void OneTimeSetup() [TearDown] public void Teardown() { + SqliteConnection.ClearAllPools(); + var testDir = new DirectoryInfo(m_TestOutputFolder); testDir.EnumerateFiles() .ToList().ForEach(f => f.Delete()); @@ -269,7 +271,13 @@ public async Task Analyze_WithPatternNoMatch_DatabaseEmpty( Assert.AreEqual(0, await Program.Main(new string[] { "analyze", analyzePath }.Concat(options.Split(" ")).ToArray())); - using var db = new SqliteConnection($"Data Source={databasePath};Version=3;New=True;Foreign Keys=False;"); + using var db = new SqliteConnection(new SqliteConnectionStringBuilder + { + DataSource = databasePath, + Mode = SqliteOpenMode.ReadWriteCreate, + Pooling = false, + ForeignKeys = false, + }.ConnectionString); db.Open(); using (var cmd = db.CreateCommand()) @@ -294,7 +302,14 @@ public async Task Analyze_WithOutputFile_DatabaseCorrect( private void ValidateDatabase(string databasePath, bool withRefs) { - using var db = new SqliteConnection($"Data Source={databasePath};Version=3;New=True;Foreign Keys=False;"); + using var db = new SqliteConnection(new SqliteConnectionStringBuilder + { + DataSource = databasePath, + Mode = SqliteOpenMode.ReadWriteCreate, + Pooling = false, + ForeignKeys = false, + }.ConnectionString); + db.Open(); using (var cmd = db.CreateCommand()) @@ -357,6 +372,8 @@ public void OneTimeSetup() [TearDown] public void Teardown() { + SqliteConnection.ClearAllPools(); + foreach (var file in new DirectoryInfo(m_TestOutputFolder).EnumerateFiles()) { file.Delete(); @@ -370,9 +387,15 @@ public async Task Analyze_PlayerData_DatabaseCorrect() var analyzePath = Path.Combine(Context.UnityDataFolder); Assert.AreEqual(0, await Program.Main(new string[] { "analyze", analyzePath, "-p", "*." })); - - using var db = new SqliteConnection($"Data Source={databasePath};Version=3;New=True;Foreign Keys=False;"); + using var db = new SqliteConnection(new SqliteConnectionStringBuilder + { + DataSource = databasePath, + Mode = SqliteOpenMode.ReadWriteCreate, + Pooling = false, + ForeignKeys = false, + }.ConnectionString); db.Open(); + using var cmd = db.CreateCommand(); cmd.CommandText = From 925d46f4aafe8a5c72e27948e26e0b248390d4da Mon Sep 17 00:00:00 2001 From: jacob-kjaer Date: Mon, 17 Feb 2025 10:51:27 +0100 Subject: [PATCH 5/9] Fix missing transaction in .sharedAssets --- Analyzer/SQLite/SQLiteWriter.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Analyzer/SQLite/SQLiteWriter.cs b/Analyzer/SQLite/SQLiteWriter.cs index fa64d6c..fcdca19 100644 --- a/Analyzer/SQLite/SQLiteWriter.cs +++ b/Analyzer/SQLite/SQLiteWriter.cs @@ -180,6 +180,9 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con 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) @@ -195,6 +198,7 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con // dirty trick to avoid inserting the scene object a second time. if (relativePath.EndsWith(".sharedAssets")) { + m_AddObjectCommand.Transaction = transaction; m_AddObjectCommand.Parameters["@id"].Value = sceneId; m_AddObjectCommand.Parameters["@object_id"].Value = 0; m_AddObjectCommand.Parameters["@serialized_file"].Value = serializedFileId; @@ -218,10 +222,9 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con ObjectIdProvider = m_ObjectIdProvider, SerializedFileIdProvider = m_SerializedFileIdProvider, LocalToDbFileId = m_LocalToDbFileId, + Transaction = transaction, }; - using var transaction = m_Database.BeginTransaction(); - m_CurrentTransaction = transaction; ctx.Transaction = transaction; try { From f93e368412d9ea8e8ef00a01947fb759ff9ed6ba Mon Sep 17 00:00:00 2001 From: jacob-kjaer Date: Mon, 17 Feb 2025 11:06:27 +0100 Subject: [PATCH 6/9] README.md: Remove M1 specific instructions as they are no longer needed --- README.md | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/README.md b/README.md index 55edaa1..7c03b23 100644 --- a/README.md +++ b/README.md @@ -82,23 +82,13 @@ The repository contains the following items: ## How to build -The projects in this solution require the .NET 6.0 SDK. You can use your favorite IDE to build them. +The projects in this solution require the .NET 9.0 SDK. You can use your favorite IDE to build them. They were tested in Visual Studio on Windows and Rider on Mac. It is also possible to build the projects from the CLI using this command: `dotnet build -c Release` -### How to build on osx-arm64 (such as M1) - -The project depends on the `System.Data.SQLite` package which is not yet supported on osx-arm64. To build and run tests -on osx-arm64 you need to use the osx-x64 architecture instead. To do so: -1. Build Unity on your target platform: - `./jam MacEditor` (the target MacEditor builds for the osx-x64 platform) -2. Copy UnityFIleSystemApi.dylib to the `UnityDataTools/UnityFileSystem` folder -3. To verify the setup in a terminal, run `dotnet test -r osx-x64` in the `UnityDataTools/UnityFileSystem.Tests` folder -4. Configure your IDE test runner to use target architecture x64 - ## Disclaimer This project is provided on an "as-is" basis and is not officially supported by Unity. It is an From 94518be1a3e4fffbb7fe6f106edd3fb0bce6ca42 Mon Sep 17 00:00:00 2001 From: jacob-kjaer Date: Tue, 18 Feb 2025 12:02:01 +0100 Subject: [PATCH 7/9] Clean up console output --- Analyzer/AnalyzerTool.cs | 23 +++++++++++++++---- Analyzer/PPtrAndCrcProcessor.cs | 2 +- Analyzer/SQLite/SQLiteWriter.cs | 17 ++++---------- TextDumper/TextDumperTool.cs | 2 +- .../TypeTreeReaders/RandomAccessReader.cs | 2 +- 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/Analyzer/AnalyzerTool.cs b/Analyzer/AnalyzerTool.cs index 82d70ba..58db3b9 100644 --- a/Analyzer/AnalyzerTool.cs +++ b/Analyzer/AnalyzerTool.cs @@ -30,6 +30,10 @@ public int Analyze(string path, string databaseName, string searchPattern, bool int lastLength = 0; foreach (var file in files) { + // Automatically ignore these annoying OS X style files meta files. + if (Path.GetFileName(file) == ".DS_Store") + continue; + try { UnityArchive archive = null; @@ -44,9 +48,11 @@ public int Analyze(string path, string databaseName, string searchPattern, bool var relativePath = Path.GetRelativePath(path, file); - Console.Write($"\rProcessing {i * 100 / files.Length}% ({i}/{files.Length}) {file}"); - writer.WriteSerializedFile(relativePath, file, Path.GetDirectoryName(file)); + + var message = $"Processing {i * 100 / files.Length}% ({i}/{files.Length}) {file}"; + Console.Write($"\rProcessing {i * 100 / files.Length}% ({i}/{files.Length}) {file}"); + lastLength = message.Length; } if (archive != null) @@ -71,22 +77,29 @@ public int Analyze(string path, string databaseName, string searchPattern, bool } catch (Exception e) { - Console.Error.WriteLine($"Error processing {node.Path} in archive {file}"); + Console.Error.WriteLine($"\rError processing {node.Path} in archive {file}{new string(' ', Math.Max(0, lastLength - message.Length))}"); + Console.Error.WriteLine(e); + Console.WriteLine(); } } } } finally { + Console.Write($"\r{new string(' ', lastLength)}"); writer.EndAssetBundle(); archive.Dispose(); } } } - catch (Exception e) + catch(NotSupportedException) { + Console.Error.WriteLine(); + //Console.Error.WriteLine($"File not supported: {file}"); // This is commented out because another codepath will output "failed to load" + } + catch (Exception e) { Console.Error.WriteLine(); - Console.Error.WriteLine($"Error processing file {file}!"); + Console.Error.WriteLine($"Error processing file: {file}"); Console.Write($"{e.GetType()}: "); Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); diff --git a/Analyzer/PPtrAndCrcProcessor.cs b/Analyzer/PPtrAndCrcProcessor.cs index 40b2d77..7fb89b2 100644 --- a/Analyzer/PPtrAndCrcProcessor.cs +++ b/Analyzer/PPtrAndCrcProcessor.cs @@ -290,7 +290,7 @@ private void ProcessManagedReferenceRegistry(TypeTreeNode node) } else { - throw new Exception("Unsupported ManagedReferenceRegistry version"); + throw new Exception($"Unsupported ManagedReferenceRegistry version {version}"); } } diff --git a/Analyzer/SQLite/SQLiteWriter.cs b/Analyzer/SQLite/SQLiteWriter.cs index fcdca19..7f8b10f 100644 --- a/Analyzer/SQLite/SQLiteWriter.cs +++ b/Analyzer/SQLite/SQLiteWriter.cs @@ -78,10 +78,10 @@ public void Begin() foreach (var handler in m_Handlers.Values) { - Console.WriteLine($"Init handler: {handler.GetType().Name}"); - Console.WriteLine($"Connection state before init: {m_Database.State}"); + // 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}"); + // Console.WriteLine($"Connection state after init: {m_Database.State}"); } @@ -289,15 +289,7 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con if (!m_SkipReferences) { - try - { - crc32 = pptrReader.Process(currentObjectId, offset, root); - } - catch (Exception e) - { - Console.Error.WriteLine(e); - throw; - } + crc32 = pptrReader.Process(currentObjectId, offset, root); } m_AddObjectCommand.Parameters["@id"].Value = currentObjectId; @@ -325,7 +317,6 @@ public void WriteSerializedFile(string relativePath, string fullPath, string con } catch (Exception e) { - Console.Error.WriteLine($"Error processing {serializedFileId} error: {e.Message}"); transaction.Rollback(); throw; } diff --git a/TextDumper/TextDumperTool.cs b/TextDumper/TextDumperTool.cs index 042d7e3..29735dd 100644 --- a/TextDumper/TextDumperTool.cs +++ b/TextDumper/TextDumperTool.cs @@ -262,7 +262,7 @@ void DumpManagedReferenceRegistry(TypeTreeNode node, ref long offset, int level) } else { - throw new Exception("Unsupported ManagedReferenceRegistry version"); + throw new Exception($"Unsupported ManagedReferenceRegistry version {version}"); } } diff --git a/UnityFileSystem/TypeTreeReaders/RandomAccessReader.cs b/UnityFileSystem/TypeTreeReaders/RandomAccessReader.cs index 7c450d9..366f97b 100644 --- a/UnityFileSystem/TypeTreeReaders/RandomAccessReader.cs +++ b/UnityFileSystem/TypeTreeReaders/RandomAccessReader.cs @@ -117,7 +117,7 @@ public RandomAccessReader(SerializedFile serializedFile, TypeTreeNode node, Unit } else { - throw new Exception("Unsupported ManagedReferenceRegistry version"); + throw new Exception($"Unsupported ManagedReferenceRegistry version {version}"); } } else if (isReferencedObject) From 7570c01fbb0c6b4a7b2f7c40b9b9bace751bbefa Mon Sep 17 00:00:00 2001 From: Alexander Degtyarev Date: Tue, 18 Feb 2025 12:38:35 +0100 Subject: [PATCH 8/9] added notes to copy latest UnityFileSystemAPI and link to sdk 9 download --- README.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 7c03b23..76b5cf3 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,11 @@ content of Unity data files. You can directly jump if your goal is to understand how to use the UnityDataTool command-line tool. The UnityFileSystemApi library is distributed in the Tools folder of the Unity editor (starting in -version 2022.1.0a14). For simplicity, it is also included in this repository. The library is +version 2022.1.0a14). For simplicity, it is also included in this repository. The library is somewhat backward compatible, which means that it can read data files generated by any previous version of -Unity. - -Note that the UnityFileSystemApi library included in this repository is a custom version containing -an additional function that is required to support the -[SerializeReference](https://docs.unity3d.com/ScriptReference/SerializeReference.html) -attribute. This version of the library will be included in future releases of Unity. - +Unity. Ideally, you should copy UnityFileSystemApi (.dll/.dylib) from Unity Editor install path +`Data/Tools/` subfolder to `UnityDataTool/UnityFileSystem/` of an Engine version that produced +serialized data you want to analyze. ## What is the purpose of the UnityFileSystemApi native library? @@ -82,15 +78,18 @@ The repository contains the following items: ## How to build -The projects in this solution require the .NET 9.0 SDK. You can use your favorite IDE to build them. +The projects in this solution require the [.NET 9.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/9.0). +You can use your favorite IDE to build them. They were tested in Visual Studio on Windows and Rider on Mac. It is also possible to build the projects from the CLI using this command: `dotnet build -c Release` -## Disclaimer +(Optional) Copying current editor `UnityFileSystemApi`(.so/.dll/.dylib) library from +`{UnityEditor Install Folder}/Data/Tools/` to `UnityDataTool/UnityFileSystem/` before building. +## Disclaimer This project is provided on an "as-is" basis and is not officially supported by Unity. It is an experimental tool provided as an example of what can be done using the UnityFileSystemApi. You can report bugs and submit pull requests, but there is no guarantee that they will be addressed. From ce9d8bfdc50517d429a4674f8bb49a1065592aa6 Mon Sep 17 00:00:00 2001 From: Alexander Degtyarev Date: Tue, 18 Feb 2025 15:00:59 +0100 Subject: [PATCH 9/9] Updated build instructions --- README.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 76b5cf3..fc7716e 100644 --- a/README.md +++ b/README.md @@ -78,16 +78,13 @@ The repository contains the following items: ## How to build -The projects in this solution require the [.NET 9.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/9.0). -You can use your favorite IDE to build them. -They were tested in Visual Studio on Windows and Rider on Mac. +1) The projects in this solution require the [.NET 9.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/9.0). +2) Copy `UnityFileSystemApi` library from UnityEditor installation +`{UnityEditor}/Data/Tools/` to `UnityDataTool/UnityFileSystem/` before building. +3) Build using `dotnet build -c Release` -It is also possible to build the projects from the CLI using this command: - -`dotnet build -c Release` - -(Optional) Copying current editor `UnityFileSystemApi`(.so/.dll/.dylib) library from -`{UnityEditor Install Folder}/Data/Tools/` to `UnityDataTool/UnityFileSystem/` before building. +Note: You can use your favorite IDE to build solution. +Tested Visual Studio and Rider on Windows and Rider on Mac. ## Disclaimer This project is provided on an "as-is" basis and is not officially supported by Unity. It is an