Skip to content

Commit 5a5f637

Browse files
Use directly parsed ObjectList for ObjectList command
This fixes ObjectList for files without TypeTrees
1 parent 94e58b8 commit 5a5f637

3 files changed

Lines changed: 80 additions & 47 deletions

File tree

Analyzer/Util/SerializedFileDetector.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -604,12 +604,6 @@ private static void ParseExtendedMetadata(BinaryReader reader, SerializedFileInf
604604
}
605605
metadata.ObjectList = objectList;
606606

607-
// m_RefTypes (version >= 20) is not located immediately after m_Types.
608-
// It appears at the end of the metadata section, after the object list,
609-
// script type list, and externals list. We must skip those three sections.
610-
if (version < SupportsRefObjectVersion)
611-
return;
612-
613607
// --- Skip the script type list ---
614608
// Per-entry layout (version >= 14, applies to all our versions):
615609
// [int32 localSerializedFileIndex]
@@ -638,6 +632,11 @@ private static void ParseExtendedMetadata(BinaryReader reader, SerializedFileInf
638632
BinaryFileHelper.ReadNullTermString(reader); // pathName
639633
}
640634

635+
// m_RefTypes (version >= 20) is not located immediately after m_Types.
636+
// It appears at the end of the metadata section
637+
if (version < SupportsRefObjectVersion)
638+
return;
639+
641640
// --- SerializeReference type list (m_RefTypes, version >= 20) ---
642641
int refTypeCount = BinaryFileHelper.ReadInt32(reader, swap);
643642
metadata.SerializedReferenceTypeTreeCount = refTypeCount;

UnityDataTool.Tests/SerializedFileCommandTests.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,49 @@ public async Task ObjectList_SharedAssets_ContainsExpectedTypes()
293293
}
294294
}
295295

296+
[Test]
297+
public async Task ObjectList_NoTypeTree_JsonFormat_OutputsExpectedValues()
298+
{
299+
var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "PlayerNoTypeTree", "level0");
300+
using var sw = new StringWriter();
301+
var currentOut = Console.Out;
302+
try
303+
{
304+
Console.SetOut(sw);
305+
306+
Assert.AreEqual(0, await Program.Main(new string[] { "sf", "objectlist", path, "-f", "json" }));
307+
308+
var output = sw.ToString();
309+
var jsonArray = JsonDocument.Parse(output).RootElement;
310+
Assert.AreEqual(7, jsonArray.GetArrayLength());
311+
312+
// Spot-check a few entries by index
313+
var first = jsonArray[0];
314+
Assert.AreEqual(1, first.GetProperty("id").GetInt64());
315+
Assert.AreEqual(1, first.GetProperty("typeId").GetInt32());
316+
Assert.AreEqual("GameObject", first.GetProperty("typeName").GetString());
317+
Assert.AreEqual(576, first.GetProperty("offset").GetInt64());
318+
Assert.AreEqual(63, first.GetProperty("size").GetInt64());
319+
320+
var third = jsonArray[2];
321+
Assert.AreEqual(3, third.GetProperty("id").GetInt64());
322+
Assert.AreEqual(104, third.GetProperty("typeId").GetInt32());
323+
Assert.AreEqual("RenderSettings", third.GetProperty("typeName").GetString());
324+
Assert.AreEqual(720, third.GetProperty("offset").GetInt64());
325+
326+
var last = jsonArray[6];
327+
Assert.AreEqual(7, last.GetProperty("id").GetInt64());
328+
Assert.AreEqual(114, last.GetProperty("typeId").GetInt32());
329+
Assert.AreEqual("MonoBehaviour", last.GetProperty("typeName").GetString());
330+
Assert.AreEqual(1200, last.GetProperty("offset").GetInt64());
331+
Assert.AreEqual(44, last.GetProperty("size").GetInt64());
332+
}
333+
finally
334+
{
335+
Console.SetOut(currentOut);
336+
}
337+
}
338+
296339
#endregion
297340

298341
#region Header Tests

UnityDataTool/SerializedFileCommands.cs

Lines changed: 32 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -33,24 +33,39 @@ public static int HandleExternalRefs(FileInfo filename, OutputFormat format)
3333

3434
public static int HandleObjectList(FileInfo filename, OutputFormat format)
3535
{
36-
if (!ValidateSerializedFile(filename.FullName, out _))
36+
// The object list is read directly from the parsed metadata rather than via UnityFileSystemApi.
37+
//
38+
// Advantages: works for any modern SerializedFile (version >= 19), including Player builds
39+
// that were compiled without TypeTrees — files that UnityFileSystemApi cannot open at all.
40+
//
41+
// Trade-offs: type names come from TypeIdRegistry rather than the file's embedded TypeTree,
42+
// so uncommon types not covered by the registry are displayed as a numeric TypeId. Files
43+
// older than version 19 (Unity 2019.1) are not supported by the metadata parser.
44+
//
45+
// These trade-offs are minor compared to the benefit of handling the common no-TypeTree case,
46+
// so there is no need to keep the UnityFileSystemApi code path.
47+
if (!ValidateSerializedFile(filename.FullName, out var fileInfo))
3748
return 1;
3849

39-
try
50+
if (!SerializedFileDetector.TryParseMetadata(filename.FullName, fileInfo, out var metadata, out var errorMessage))
4051
{
41-
using var sf = UnityFileSystem.OpenSerializedFile(filename.FullName);
42-
if (format == OutputFormat.Json)
43-
OutputObjectListJson(sf);
44-
else
45-
OutputObjectListText(sf);
46-
return 0;
52+
Console.Error.WriteLine($"Error: Failed to parse object list for: {filename.FullName}");
53+
Console.Error.WriteLine(errorMessage);
54+
return 1;
4755
}
48-
catch (Exception err) when (err is NotSupportedException || err is FileFormatException)
56+
57+
if (metadata.ObjectList == null)
4958
{
50-
Console.Error.WriteLine($"Error opening SerializedFile: {filename.FullName}");
51-
Console.Error.WriteLine(err.Message);
59+
Console.Error.WriteLine($"Error: Object list could not be parsed for: {filename.FullName}");
5260
return 1;
5361
}
62+
63+
if (format == OutputFormat.Json)
64+
OutputObjectListJson(metadata.ObjectList);
65+
else
66+
OutputObjectListText(metadata.ObjectList);
67+
68+
return 0;
5469
}
5570

5671
public static int HandleHeader(FileInfo filename, OutputFormat format)
@@ -167,36 +182,27 @@ private static void OutputExternalRefsJson(SerializedFile sf)
167182
Console.WriteLine(json);
168183
}
169184

170-
private static void OutputObjectListText(SerializedFile sf)
185+
private static void OutputObjectListText(ObjectInfo[] objects)
171186
{
172-
var objects = sf.Objects;
173-
174-
// Print header
175187
Console.WriteLine($"{"Id",-20} {"Type",-40} {"Offset",-15} {"Size",-15}");
176188
Console.WriteLine(new string('-', 90));
177189

178190
foreach (var obj in objects)
179-
{
180-
string typeName = GetTypeName(sf, obj);
181-
Console.WriteLine($"{obj.Id,-20} {typeName,-40} {obj.Offset,-15} {obj.Size,-15}");
182-
}
191+
Console.WriteLine($"{obj.Id,-20} {TypeIdRegistry.GetTypeName(obj.TypeId),-40} {obj.Offset,-15} {obj.Size,-15}");
183192
}
184193

185-
private static void OutputObjectListJson(SerializedFile sf)
194+
private static void OutputObjectListJson(ObjectInfo[] objects)
186195
{
187-
var objects = sf.Objects;
188-
var jsonArray = new object[objects.Count];
196+
var jsonArray = new object[objects.Length];
189197

190-
for (int i = 0; i < objects.Count; i++)
198+
for (int i = 0; i < objects.Length; i++)
191199
{
192200
var obj = objects[i];
193-
string typeName = GetTypeName(sf, obj);
194-
195201
jsonArray[i] = new
196202
{
197203
id = obj.Id,
198204
typeId = obj.TypeId,
199-
typeName = typeName,
205+
typeName = TypeIdRegistry.GetTypeName(obj.TypeId),
200206
offset = obj.Offset,
201207
size = obj.Size
202208
};
@@ -206,21 +212,6 @@ private static void OutputObjectListJson(SerializedFile sf)
206212
Console.WriteLine(json);
207213
}
208214

209-
private static string GetTypeName(SerializedFile sf, ObjectInfo obj)
210-
{
211-
try
212-
{
213-
// Try to get type name from TypeTree first (most accurate)
214-
var root = sf.GetTypeTreeRoot(obj.Id);
215-
return root.Type;
216-
}
217-
catch
218-
{
219-
// Fall back to registry if TypeTree is not available
220-
return TypeIdRegistry.GetTypeName(obj.TypeId);
221-
}
222-
}
223-
224215
private static void OutputHeaderText(SerializedFileInfo info)
225216
{
226217
Console.WriteLine($"{"Version",-20} {info.Version}");

0 commit comments

Comments
 (0)