diff --git a/native/libspreads_lmdb.dylib b/native/libspreads_lmdb.dylib new file mode 100755 index 0000000..480825e Binary files /dev/null and b/native/libspreads_lmdb.dylib differ diff --git a/src/Unity.Cli/Commands_RunAssetDb.cs b/src/Unity.Cli/Commands_RunAssetDb.cs index 776afcb..46cba58 100644 --- a/src/Unity.Cli/Commands_RunAssetDb.cs +++ b/src/Unity.Cli/Commands_RunAssetDb.cs @@ -98,12 +98,17 @@ void DumpTables(AssetLmdb db, IEnumerable specs) foreach (var spec in specs) { + if (!config.OptCombined) { var path = outDir.Combine($"{db.Name}-{spec.TableName}"); dump = new DumpContext(path, config); } + // Data size in tables can vary with DbVersions. We filter them out here + if (spec.VersionCompatibliity != null && !spec.VersionCompatibliity.Contains(db.DbVersion)) + continue; + db.DumpTable(dump!, db, spec); if (!config.OptCombined) diff --git a/src/Unity.Cli/Unity.Cli.csproj b/src/Unity.Cli/Unity.Cli.csproj index 8b174c8..de62d22 100644 --- a/src/Unity.Cli/Unity.Cli.csproj +++ b/src/Unity.Cli/Unity.Cli.csproj @@ -41,4 +41,10 @@ + + + PreserveNewest + + + diff --git a/src/Unity/AssetDb/AssetLmdb.cs b/src/Unity/AssetDb/AssetLmdb.cs index 5a16f5b..85b5864 100644 --- a/src/Unity/AssetDb/AssetLmdb.cs +++ b/src/Unity/AssetDb/AssetLmdb.cs @@ -21,7 +21,7 @@ public AssetLmdb(NPath dbPath, params uint[] supportedVersions) : base(dbPath) var supportedVersionsText = supportedVersions .Select(NiceUint) .StringJoin(", "); - throw new InvalidOperationException($"Unsupported {Name} version {NiceUint(DbVersion)} (supported: {supportedVersionsText})"); + throw new InvalidOperationException($"Unsupported {Name} version {NiceUint(DbVersion)} ({DbVersion}) (supported: {supportedVersionsText})"); } } @@ -94,7 +94,7 @@ public void DumpTable(DumpContext dump, AssetLmdb db, TableDumpSpec spec) [UsedImplicitly] public record AssetLmdbInfo(string Name, string Version, string[] TableNames); -public record TableDumpSpec(string TableName, string CsvFields, bool UniqueKeys, Action Dump); +public record TableDumpSpec(string TableName, string CsvFields, bool UniqueKeys, uint[]? VersionCompatibliity, Action Dump); public struct DumpConfig { diff --git a/src/Unity/AssetDb/Attributes.cs b/src/Unity/AssetDb/Attributes.cs index 1780257..be46c3f 100644 --- a/src/Unity/AssetDb/Attributes.cs +++ b/src/Unity/AssetDb/Attributes.cs @@ -16,6 +16,8 @@ public AssetLmdbTableAttribute(string tableName, string csvFields) public bool UniqueKeys { get; set; } + public uint[]? VersionCompatibility { get; set; } + public static TableDumpSpec[] CreateTableDumpSpecs(Type type) { var expected = new[] { typeof(DumpContext), typeof(DirectBuffer), typeof(DirectBuffer) }; @@ -32,7 +34,7 @@ public static TableDumpSpec[] CreateTableDumpSpecs(Type type) throw new InvalidOperationException($"Method {m.DeclaringType}.{m.Name} is not `void {m.Name}(DumpContext, DirectBuffer, DirectBuffer)`"); return new TableDumpSpec( - attr._tableName, attr._csvFields, attr.UniqueKeys, + attr._tableName, attr._csvFields, attr.UniqueKeys, attr.VersionCompatibility, (c, k, v) => m.Invoke(null, [c, k, v])); }) .Where(s => s != null) diff --git a/src/Unity/AssetDb/DirectBufferExtensions.cs b/src/Unity/AssetDb/DirectBufferExtensions.cs index 812435c..6393a45 100644 --- a/src/Unity/AssetDb/DirectBufferExtensions.cs +++ b/src/Unity/AssetDb/DirectBufferExtensions.cs @@ -23,7 +23,7 @@ public static T Read(this ref DirectBuffer @this) where T : unmanaged public static T ReadExpectEnd(this in DirectBuffer @this) where T : unmanaged { if (@this.Length != Unsafe.SizeOf()) - throw new InvalidOperationException("Did not consume entire value"); + throw new InvalidOperationException($"Did not consume entire value. Expected {@this.Length}, actual: {Unsafe.SizeOf()}"); return @this.Read(0); } diff --git a/src/Unity/AssetDb/SourceAssetLmdb.cs b/src/Unity/AssetDb/SourceAssetLmdb.cs index 7894a99..fae249b 100644 --- a/src/Unity/AssetDb/SourceAssetLmdb.cs +++ b/src/Unity/AssetDb/SourceAssetLmdb.cs @@ -8,7 +8,7 @@ namespace OkTools.Unity.AssetDb; public static class SourceAssetLmdb { - static readonly uint[] k_expectedDbVersions = [9, 10, 0x218FD4A3]; + static readonly uint[] k_expectedDbVersions = [9, 10, 0x218FD4A3, 0xB7728EEA]; public static AssetLmdb OpenLmdb(NPath projectRoot) => new(projectRoot.Combine(UnityProjectConstants.SourceAssetDbNPath), k_expectedDbVersions); @@ -99,7 +99,7 @@ public static void DumpGuidToPath(DumpContext dump, DirectBuffer key, DirectBuff dump.Json!.WriteString(unityGuid.ToString(), path); } - [AssetLmdbTable("hash", "Path,Hash,Time,FileSize,IsUntrusted", UniqueKeys = true)] + [AssetLmdbTable("hash", "Path,Hash,Time,FileSize,IsUntrusted", UniqueKeys = true, VersionCompatibility = [9, 10, 0x218FD4A3])] public static void DumpPathToHash(DumpContext dump, DirectBuffer key, DirectBuffer value) { // HashDB.cpp: HashDB::m_pPathToHash @@ -122,6 +122,28 @@ public static void DumpPathToHash(DumpContext dump, DirectBuffer key, DirectBuff } } + [AssetLmdbTable("hash", "Path,Hash,Time,FileSize,IsUntrusted", UniqueKeys = true, VersionCompatibility = [0xB7728EEA])] + public static void DumpPathToHash2(DumpContext dump, DirectBuffer key, DirectBuffer value) + { + // HashDB.cpp: HashDB::m_pPathToHash + + var path = key.ToAsciiString(); + var hash = value.ReadExpectEnd(); + + if (dump.Csv != null) + dump.Csv.Write($"{path},{hash.hash},{hash.TimeAsDateTime},{hash.isUntrusted},"); + else + { + dump.Json!.WriteStartObject(path); + + dump.Json.WriteString("Hash", hash.hash.ToString()); + dump.Json.WriteString("Time", hash.TimeAsDateTime); + dump.Json.WriteBoolean("IsUntrusted", hash.isUntrusted); + + dump.Json.WriteEndObject(); + } + } + [AssetLmdbTable("Misc", "Name,Value0,Value1,...", UniqueKeys = true)] public static void DumpMisc(DumpContext dump, DirectBuffer key, DirectBuffer value) { diff --git a/src/Unity/AssetDb/SourceAssetLmdbSchema.cs b/src/Unity/AssetDb/SourceAssetLmdbSchema.cs index 1d1508f..0041487 100644 --- a/src/Unity/AssetDb/SourceAssetLmdbSchema.cs +++ b/src/Unity/AssetDb/SourceAssetLmdbSchema.cs @@ -55,3 +55,12 @@ struct HashDBValue // Modules/AssetDatabase/Editor/V2/HashDB.h public DateTime TimeAsDateTime => new(time); // C++ DateTime not binary compatible because extra field in C# version, but easy to convert (they both use the same ticks epoch+resolution) } + +struct HashDBValueNoFileSize // Modules/AssetDatabase/Editor/V2/HashDB.h +{ + public Hash128 hash; + public long time; + public bool isUntrusted; + + public DateTime TimeAsDateTime => new(time); // C++ DateTime not binary compatible because extra field in C# version, but easy to convert (they both use the same ticks epoch+resolution) +} diff --git a/src/Unity/Unity.cs b/src/Unity/Unity.cs index 4ae6532..e21e677 100644 --- a/src/Unity/Unity.cs +++ b/src/Unity/Unity.cs @@ -48,7 +48,7 @@ internal static IReadOnlyList FindUnityProcessesForProject(NPath projec foreach (var unityProcess in Process.GetProcessesByName(UnityConstants.UnityProcessName)) { - var workingDir = NativeWindows.SafeGetProcessCurrentDirectory(unityProcess.Id)?.ToNPath(); + var workingDir = "";//NativeWindows.SafeGetProcessCurrentDirectory(unityProcess.Id)?.ToNPath(); if (workingDir == projectPath) matches.Add(unityProcess); else @@ -63,7 +63,7 @@ internal static IReadOnlyList FindUnityProcessesForProject(NPath projec { foreach (var unityProcess in unityProcesses.Where(p => p.MainWindowHandle != default)) { - var unityCommandLine = NativeWindows.SafeGetProcessCommandLine(unityProcess.Id); + var unityCommandLine = "";//NativeWindows.SafeGetProcessCommandLine(unityProcess.Id); if (unityCommandLine == null) continue;