18 Commits
Author SHA1 Message Date
dependabot[bot] 94549d10ee Bump Microsoft.SourceLink.GitHub from 10.0.300 to 10.0.301
---
updated-dependencies:
- dependency-name: Microsoft.SourceLink.GitHub
  dependency-version: 10.0.301
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-07-24 21:10:09 -07:00
dependabot[bot] 1a2c247668 Bump actions/setup-dotnet from 5 to 6
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 5 to 6.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-07-21 14:09:59 -07:00
ds5678 f94757d204 Bump version to 2.0.0 2026-07-03 11:17:38 -07:00
ds5678 474fe30489 Revert "Do not archive CI artifacts"
This reverts commit 70c3b6ca93.
2026-07-01 23:56:45 -07:00
ds5678 70c3b6ca93 Do not archive CI artifacts 2026-07-01 23:19:46 -07:00
ds5678 6b72bf855d Update binary format to support Unity 6.6 common string 2026-07-01 22:47:10 -07:00
ds5678 be9d53f317 Bump version to 1.2.1
This is the last version before 2.0
2026-07-01 21:31:02 -07:00
ds5678 a7e3d89b2d Ensure that json serialization uses minimal character escaping 2026-07-01 21:24:47 -07:00
ds5678 21eca606fd Remove Size and TypeIndex from UnityClass 2026-06-30 14:56:23 -07:00
ds5678 8bef636a8f Remove Level and Index from UnityNode 2026-06-30 14:42:48 -07:00
ds5678 7ed791b58c Remove Version from UnityInfo 2026-06-30 14:35:11 -07:00
ds5678 236236fed8 Merge indented and not indented json serializer contexts 2026-06-30 14:22:36 -07:00
ds5678 019d733bb2 Refactor to use newer coding conventions 2026-06-30 14:12:34 -07:00
ds5678 7663a53449 Replace Assert.Multiple with Assert.EnterMultipleScope
Updated test methods to use Assert.EnterMultipleScope instead of Assert.Multiple for grouping multiple assertions, reflecting the preferred NUnit API. This change affects EngineAssetsTests.cs, TpkFileTests.cs, and CommonStringTests.cs.
2026-06-30 13:08:23 -07:00
ds5678 f9e25d911f Update dependencies
- Updated SharpCompress to 0.49.1 in Tpk.csproj and removed from Tpk.ConsoleApp.csproj
- Bumped Microsoft.SourceLink.GitHub to 10.0.300 in Tpk and Tpk.TypeTrees.Json
- Updated test dependencies: Microsoft.NET.Test.Sdk, NUnit, NUnit.Analyzers, and coverlet.collector
2026-06-30 13:05:16 -07:00
dependabot[bot] a4f6013e45 Bump actions/checkout from 6 to 7
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-06-26 19:34:18 -07:00
dependabot[bot] 1b0a2b3082 Bump NUnit.Analyzers from 4.12.0 to 4.13.0
---
updated-dependencies:
- dependency-name: NUnit.Analyzers
  dependency-version: 4.13.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: NUnit.Analyzers
  dependency-version: 4.13.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-05-17 21:41:34 -07:00
dependabot[bot] b5b5ace321 Bump SharpCompress from 0.47.3 to 0.47.4
---
updated-dependencies:
- dependency-name: SharpCompress
  dependency-version: 0.47.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-04-24 23:26:52 -07:00
29 changed files with 270 additions and 283 deletions

No files matched your search

+3 -3
View File
@@ -27,16 +27,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Tpk Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Setup .NET
uses: actions/setup-dotnet@v5
uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x
- name: Build
run: dotnet build /p:Configuration=Release
working-directory: ./Tpk.ConsoleApp/
- name: Checkout DocumentationDumps Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
repository: 'AssetRipper/DocumentationDumps'
path: DocumentationDumps
+2 -2
View File
@@ -12,9 +12,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Setup .NET
uses: actions/setup-dotnet@v5
uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x
- name: Restore dependencies
+3 -3
View File
@@ -27,16 +27,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Tpk Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Setup .NET
uses: actions/setup-dotnet@v5
uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x
- name: Build
run: dotnet build /p:Configuration=Release
working-directory: ./Tpk.ConsoleApp/
- name: Checkout TypeTreeDumps Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
repository: 'AssetRipper/TypeTreeDumps'
sparse-checkout: 'InfoJson'
+1 -1
View File
@@ -9,7 +9,7 @@
<Authors>ds5678</Authors>
<Company>AssetRipper</Company>
<VersionPrefix>1.2.0</VersionPrefix>
<VersionPrefix>2.0.0</VersionPrefix>
<RepositoryUrl>https://github.com/AssetRipper/Tpk</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryType>git</RepositoryType>
-4
View File
@@ -6,10 +6,6 @@
<AssemblyName>AssetRipper.Tpk.ConsoleApp</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SharpCompress" Version="0.47.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Tpk.TypeTrees.Json\Tpk.TypeTrees.Json.csproj" />
<ProjectReference Include="..\Tpk\Tpk.csproj" />
+37 -28
View File
@@ -1,4 +1,5 @@
using AssetRipper.Primitives;
using AssetRipper.Tpk.Shared;
using AssetRipper.Tpk.TypeTrees;
using AssetRipper.Tpk.TypeTrees.Json;
using System.Collections.Generic;
@@ -28,44 +29,37 @@ namespace AssetRipper.Tpk.ConsoleApp
private static TpkTypeTreeBlob Create(IEnumerable<string> pathsOrderedByUnityVersion)
{
return Create(pathsOrderedByUnityVersion.Select(path => UnityInfo.ReadFromJsonFile(path)));
return Create(pathsOrderedByUnityVersion.Select(path =>
{
string versionString = Path.GetFileNameWithoutExtension(path);
UnityVersion version = UnityVersion.Parse(versionString);
UnityInfo info = UnityInfo.ReadFromJsonFile(path);
return (version, info);
}));
}
private static TpkTypeTreeBlob Create(IEnumerable<UnityInfo> infosOrderedByUnityVersion)
private static TpkTypeTreeBlob Create(IEnumerable<(UnityVersion Version, UnityInfo Info)> infosOrderedByUnityVersion)
{
TpkTypeTreeBlob blob = new TpkTypeTreeBlob();
blob.CommonString.Add(UnityVersion.MinVersion, 0);
byte latestCommonStringCount = 0;
List<string> commonStrings = new List<string>();
Dictionary<int, string> latestUnityClassesDumped = new Dictionary<int, string>();
Dictionary<int, TpkClassInformation> classDictionary = new Dictionary<int, TpkClassInformation>();
List<TpkCommonString.Entry> commonStrings = [];
Dictionary<int, string> latestUnityClassesDumped = [];
Dictionary<int, TpkClassInformation> classDictionary = [];
foreach (UnityInfo info in infosOrderedByUnityVersion)
foreach ((UnityVersion version, UnityInfo? info) in infosOrderedByUnityVersion)
{
Console.WriteLine(info.Version);
UnityVersion version = UnityVersion.Parse(info.Version);
Console.WriteLine(version.ToString());
blob.Versions.Add(version);
if (info.Strings.Count != latestCommonStringCount)
if (!Same(info.Strings, commonStrings, blob.StringBuffer))
{
latestCommonStringCount = (byte)info.Strings.Count;
blob.CommonString.Add(version, latestCommonStringCount);
}
for (int i = 0; i < info.Strings.Count; i++)
{
if (i < commonStrings.Count)
commonStrings.Clear();
commonStrings.EnsureCapacity(commonStrings.Count);
foreach (UnityString unityString in info.Strings)
{
if (info.Strings[i].String != commonStrings[i])
{
throw new Exception($"String inequality at index {i} for version {version}");
}
}
else
{
commonStrings.Add(info.Strings[i].String);
commonStrings.Add(new TpkCommonString.Entry((ushort)unityString.Index, unityString.String, blob.StringBuffer));
}
blob.CommonString.Add(version, commonStrings.ToArray());
}
foreach (UnityClass unityClass in info.Classes)
@@ -115,8 +109,7 @@ namespace AssetRipper.Tpk.ConsoleApp
blob.ClassInformation.AddRange(classDictionary.Values);
blob.CommonString.SetIndices(blob.StringBuffer, commonStrings);
//About 21k / 65k
//About 26k / 65k
Console.WriteLine($"Node buffer has {blob.NodeBuffer.Count} entries, which is {GetUShortPercent(blob.NodeBuffer.Count)}% of its maximum {ushort.MaxValue} entries");
//About 7k / 65k
Console.WriteLine($"String buffer has {blob.StringBuffer.Count} entries, which is {GetUShortPercent(blob.StringBuffer.Count)}% of its maximum {ushort.MaxValue} entries");
@@ -126,6 +119,22 @@ namespace AssetRipper.Tpk.ConsoleApp
return blob;
}
private static bool Same(List<UnityString> jsonStrings, List<TpkCommonString.Entry> tpkEntries, TpkStringBuffer stringBuffer)
{
if (jsonStrings.Count != tpkEntries.Count)
{
return false;
}
for (int i = 0; i < jsonStrings.Count; i++)
{
if (jsonStrings[i].String != tpkEntries[i].ToString(stringBuffer))
{
return false;
}
}
return true;
}
private static int GetUShortPercent(int value) => value * 100 / ushort.MaxValue;
}
}
+6 -21
View File
@@ -14,9 +14,9 @@ namespace AssetRipper.Tpk.ConsoleApp
/// </summary>
/// <param name="zipFilePath"></param>
/// <returns>A list ordered by Unity version</returns>
public static IEnumerable<UnityInfo> ReadUnityInfoFromZipFile(string zipFilePath)
public static IEnumerable<(UnityVersion Version, UnityInfo Info)> ReadUnityInfoFromZipFile(string zipFilePath)
{
List<UnityInfo> list = new();
List<(UnityVersion Version, UnityInfo Info)> list = new();
using FileStream fileStream = File.OpenRead(zipFilePath);
using IWritableArchive<ZipWriterOptions> archive = ZipArchive.OpenArchive(fileStream);
@@ -24,37 +24,22 @@ namespace AssetRipper.Tpk.ConsoleApp
{
if (!entry.IsDirectory && (entry.Key ?? "").EndsWith(".json", StringComparison.Ordinal))
{
string versionString = Path.GetFileNameWithoutExtension(entry.Key ?? "");
UnityVersion version = UnityVersion.Parse(versionString);
using MemoryStream unzippedFileStream = new MemoryStream();
entry.WriteTo(unzippedFileStream);
unzippedFileStream.Position = 0;
UnityInfo? info = UnityInfo.FromStream(unzippedFileStream);
if (info is not null)
{
list.Add(info);
list.Add((version, info));
}
}
}
list.Sort(CompareUnityInfo);
list.Sort((a, b) => a.Version.CompareTo(b.Version));
return list;
}
/// <summary>
/// Compare two UnityInfo by their versions
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns>
/// Less than zero: a precedes b<br />
/// Zero: equivalent position<br />
/// Greater than zero: a follows b
/// </returns>
private static int CompareUnityInfo(UnityInfo a, UnityInfo b)
{
UnityVersion versionA = UnityVersion.Parse(a.Version);
UnityVersion versionB = UnityVersion.Parse(b.Version);
return versionA.CompareTo(versionB);
}
}
}
+4 -4
View File
@@ -19,12 +19,12 @@ public class EngineAssetsTests
originalBlob.Data.Add(new KeyValuePair<UnityVersion, string>(new UnityVersion(4), RandomUtils.RandomString()));
byte[] writtenData = originalBlob.ToBinary();
TpkEngineAssetsBlob readBlob = TpkDataBlob.FromBinary<TpkEngineAssetsBlob>(writtenData);
Assert.Multiple(() =>
using (Assert.EnterMultipleScope())
{
Assert.That(readBlob.CreationTime, Is.EqualTo(originalBlob.CreationTime));
Assert.That(readBlob.Versions, Is.EqualTo(originalBlob.Versions));
Assert.That(readBlob.Data, Is.EqualTo(originalBlob.Data));
});
}
}
[Test]
@@ -33,11 +33,11 @@ public class EngineAssetsTests
TpkEngineAssetsBlob originalBlob = new();
byte[] writtenData = originalBlob.ToBinary();
TpkEngineAssetsBlob readBlob = TpkDataBlob.FromBinary<TpkEngineAssetsBlob>(writtenData);
Assert.Multiple(() =>
using (Assert.EnterMultipleScope())
{
Assert.That(readBlob.CreationTime, Is.EqualTo(originalBlob.CreationTime));
Assert.That(readBlob.Versions, Is.EqualTo(originalBlob.Versions));
Assert.That(readBlob.Data, Is.EqualTo(originalBlob.Data));
});
}
}
}
+5 -5
View File
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RootNamespace>AssetRipper.Tpk.Tests</RootNamespace>
@@ -7,14 +7,14 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="NUnit" Version="4.5.1" />
<PackageReference Include="NUnit.Analyzers" Version="4.12.0">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.7.0" />
<PackageReference Include="NUnit" Version="4.6.1" />
<PackageReference Include="NUnit.Analyzers" Version="4.14.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NUnit3TestAdapter" Version="6.2.0" />
<PackageReference Include="coverlet.collector" Version="8.0.1">
<PackageReference Include="coverlet.collector" Version="10.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
+2 -2
View File
@@ -9,13 +9,13 @@ namespace AssetRipper.Tpk.Tests
{
TpkFile file = CreateTpkFile();
byte[] data = file.WriteToMemory();
Assert.Multiple(() =>
using (Assert.EnterMultipleScope())
{
Assert.That(data[0], Is.EqualTo((byte)'T'));
Assert.That(data[1], Is.EqualTo((byte)'P'));
Assert.That(data[2], Is.EqualTo((byte)'K'));
Assert.That(data[3], Is.EqualTo((byte)'*'));
});
}
}
private static TpkFile CreateTpkFile()
+32 -12
View File
@@ -1,6 +1,7 @@
using AssetRipper.Primitives;
using AssetRipper.Tpk.TypeTrees;
using NUnit.Framework;
using System.IO;
namespace AssetRipper.Tpk.Tests.TypeTrees
{
@@ -9,35 +10,54 @@ namespace AssetRipper.Tpk.Tests.TypeTrees
private static UnityVersion Unity3 => new UnityVersion(3, 0, 0, UnityVersionType.Final, 1);
private static UnityVersion Unity4 => new UnityVersion(4, 0, 0, UnityVersionType.Final, 1);
private static UnityVersion Unity5 => new UnityVersion(5, 0, 0, UnityVersionType.Final, 1);
private static UnityVersion Unity6 => new UnityVersion(6, 0, 0, UnityVersionType.Final, 1);
private static UnityVersion Unity7 => new UnityVersion(7, 0, 0, UnityVersionType.Final, 1);
private static UnityVersion Unity6 => new UnityVersion(6000, 0, 0, UnityVersionType.Final, 1);
private static UnityVersion Unity7 => new UnityVersion(7000, 0, 0, UnityVersionType.Final, 1);
[Test]
public static void CountIsCorrectForEmptyCommonString()
{
TpkCommonString commonString = new();
Assert.That(commonString.GetCount(Unity5), Is.EqualTo(0));
Assert.That(commonString.GetEntries(Unity5), Is.Empty);
}
[Test]
public static void CountIsCorrectForNormalUse()
{
TpkCommonString commonString = MakeCommonString();
Assert.Multiple(() =>
using (Assert.EnterMultipleScope())
{
Assert.That(commonString.GetCount(Unity3), Is.EqualTo(5));
Assert.That(commonString.GetCount(Unity4), Is.EqualTo(5));
Assert.That(commonString.GetCount(Unity5), Is.EqualTo(5));
Assert.That(commonString.GetCount(Unity6), Is.EqualTo(10));
Assert.That(commonString.GetCount(Unity7), Is.EqualTo(10));
});
Assert.That(commonString.GetEntries(Unity3), Has.Length.EqualTo(5));
Assert.That(commonString.GetEntries(Unity4), Has.Length.EqualTo(5));
Assert.That(commonString.GetEntries(Unity5), Has.Length.EqualTo(5));
Assert.That(commonString.GetEntries(Unity6), Has.Length.EqualTo(10));
Assert.That(commonString.GetEntries(Unity7), Has.Length.EqualTo(10));
}
}
[Test]
public static void ReadingAndWritingUseSameBytes()
{
TpkCommonString commonString = MakeCommonString();
MemoryStream stream = new();
BinaryWriter writer = new(stream);
commonString.Write(writer);
writer.Flush();
int bytesWritten = (int)stream.Length;
stream.Position = 0;
BinaryReader reader = new(stream);
TpkCommonString readCommonString = new();
readCommonString.Read(reader);
int bytesRead = (int)stream.Position;
Assert.That(bytesRead, Is.EqualTo(bytesWritten));
}
private static TpkCommonString MakeCommonString()
{
TpkCommonString commonString = new();
commonString.Add(Unity4, 5);
commonString.Add(Unity6, 10);
commonString.Add(Unity4, new TpkCommonString.Entry[5]);
commonString.Add(Unity6, new TpkCommonString.Entry[10]);
return commonString;
}
}
@@ -7,14 +7,14 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="NUnit" Version="4.5.1" />
<PackageReference Include="NUnit.Analyzers" Version="4.12.0">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.7.0" />
<PackageReference Include="NUnit" Version="4.6.1" />
<PackageReference Include="NUnit.Analyzers" Version="4.14.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NUnit3TestAdapter" Version="6.2.0" />
<PackageReference Include="coverlet.collector" Version="8.0.1">
<PackageReference Include="coverlet.collector" Version="10.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
+2 -4
View File
@@ -30,8 +30,6 @@ namespace AssetRipper.Tpk.TypeTrees.Json
result.Module = "";
//TypeID gets set elsewhere
result.Base = stringBuffer[source.Base];
result.Size = -1;
//Type index is ignored
result.IsAbstract = source.Flags.IsAbstract();
result.IsSealed = source.Flags.IsSealed();
result.IsEditorOnly = source.Flags.IsEditorOnly();
@@ -39,11 +37,11 @@ namespace AssetRipper.Tpk.TypeTrees.Json
result.IsStripped = source.Flags.IsStripped();
if (source.EditorRootNode != ushort.MaxValue)
{
result.EditorRootNode = NodeConversion.Convert(nodeBuffer[source.EditorRootNode], stringBuffer, nodeBuffer, 0, 0, out var _);
result.EditorRootNode = NodeConversion.Convert(nodeBuffer[source.EditorRootNode], stringBuffer, nodeBuffer);
}
if (source.ReleaseRootNode != ushort.MaxValue)
{
result.ReleaseRootNode = NodeConversion.Convert(nodeBuffer[source.ReleaseRootNode], stringBuffer, nodeBuffer, 0, 0, out var _);
result.ReleaseRootNode = NodeConversion.Convert(nodeBuffer[source.ReleaseRootNode], stringBuffer, nodeBuffer);
}
return result;
}
+11 -14
View File
@@ -24,26 +24,23 @@ namespace AssetRipper.Tpk.TypeTrees.Json
return nodeBuffer.AddNode(nodeData);
}
public static UnityNode Convert(TpkUnityNode nodeData, TpkStringBuffer stringBuffer, TpkUnityNodeBuffer nodeBuffer, byte level, int index, out int lastIndexUsed)
public static UnityNode Convert(TpkUnityNode nodeData, TpkStringBuffer stringBuffer, TpkUnityNodeBuffer nodeBuffer)
{
UnityNode result = new UnityNode();
result.TypeName = stringBuffer[nodeData.TypeName];
result.Name = stringBuffer[nodeData.Name];
result.Level = level;
result.ByteSize = nodeData.ByteSize;
result.Index = index;
result.Version = nodeData.Version;
result.TypeFlags = nodeData.TypeFlags;
result.MetaFlag = nodeData.MetaFlag;
UnityNode result = new()
{
TypeName = stringBuffer[nodeData.TypeName],
Name = stringBuffer[nodeData.Name],
ByteSize = nodeData.ByteSize,
Version = nodeData.Version,
TypeFlags = nodeData.TypeFlags,
MetaFlag = nodeData.MetaFlag,
};
byte levelPlus = unchecked((byte)(level + 1U));
lastIndexUsed = index;
int subNodeCount = nodeData.SubNodes.Length;
result.SubNodes = new List<UnityNode>(subNodeCount);
for (int i = 0; i < subNodeCount; i++)
{
result.SubNodes.Add(Convert(nodeBuffer[nodeData.SubNodes[i]], stringBuffer, nodeBuffer, levelPlus, index + 1, out lastIndexUsed));
index = lastIndexUsed;
result.SubNodes.Add(Convert(nodeBuffer[nodeData.SubNodes[i]], stringBuffer, nodeBuffer));
}
return result;
+1 -1
View File
@@ -16,7 +16,7 @@
<ItemGroup>
<PackageReference Include="AssetRipper.HashAlgorithms" Version="1.0.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.201">
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.301">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
+20 -27
View File
@@ -1,33 +1,31 @@
using System.Text.Json;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace AssetRipper.Tpk.TypeTrees.Json
{
public sealed class UnityClass
{
private string name = "";
private string @namespace = "";
private string fullName = "";
private string module = "";
private string @base = "";
private List<string> derived = new();
/// <summary>
/// The name of the class not including the namespace
/// </summary>
public string Name { get => name; set => name = value ?? ""; }
[AllowNull]
public string Name { get; set => field = value ?? ""; } = "";
/// <summary>
/// The namespace of the class if it exists
/// </summary>
public string Namespace { get => @namespace; set => @namespace = value ?? ""; }
[AllowNull]
public string Namespace { get; set => field = value ?? ""; } = "";
/// <summary>
/// The full name of the class including the namespace but not an assembly specification
/// </summary>
public string FullName { get => fullName; set => fullName = value ?? ""; }
[AllowNull]
public string FullName { get; set => field = value ?? ""; } = "";
/// <summary>
/// The module containing the class
/// </summary>
public string Module { get => module; set => module = value ?? ""; }
[AllowNull]
public string Module { get; set => field = value ?? ""; } = "";
/// <summary>
/// The unique number used to identify the class
/// </summary>
@@ -35,11 +33,13 @@ namespace AssetRipper.Tpk.TypeTrees.Json
/// <summary>
/// The name of the base class if it exists. Namespace not included
/// </summary>
public string Base { get => @base; set => @base = value ?? ""; }
[AllowNull]
public string Base { get; set => field = value ?? ""; } = "";
/// <summary>
/// The names of the classes that directly derive from this. Namespaces not included
/// </summary>
public List<string> Derived { get => derived; set => derived = value ?? new(); }
[AllowNull]
public List<string> Derived { get; set => field = value ?? []; } = [];
/// <summary>
/// The count of all classes that descend from this class<br/>
/// It includes this class, so the count is always positive<br/>
@@ -47,14 +47,6 @@ namespace AssetRipper.Tpk.TypeTrees.Json
/// </summary>
public uint DescendantCount { get; set; }
/// <summary>
/// The size in bytes of one object. Doesn't include alignments. May be wildly inaccurate, especially for classes with variable size.
/// </summary>
public int Size { get; set; }
/// <summary>
/// The zero based index of this class in the list of acquired classes. Doesn't mean much.
/// </summary>
public uint TypeIndex { get; set; }
/// <summary>
/// Is the class abstract?
/// </summary>
public bool IsAbstract { get; set; }
@@ -81,7 +73,9 @@ namespace AssetRipper.Tpk.TypeTrees.Json
/// <summary>
/// The constructor used in json deserialization
/// </summary>
public UnityClass() { }
public UnityClass()
{
}
/// <summary>
/// The constructor used to make dependent class definitions
@@ -100,7 +94,6 @@ namespace AssetRipper.Tpk.TypeTrees.Json
TypeID = -1;
Derived = new List<string>();
DescendantCount = 1;
Size = mainRootNode.ByteSize;
IsAbstract = false;
IsSealed = true;
IsEditorOnly = releaseRootNode == null;
@@ -153,13 +146,13 @@ namespace AssetRipper.Tpk.TypeTrees.Json
public string ToJsonString(bool indented = false)
{
return indented
? JsonSerializer.Serialize(this, UnityInfoSerializerContextIndented.Default.UnityClass)
: JsonSerializer.Serialize(this, UnityInfoSerializerContextNotIndented.Default.UnityClass);
? JsonSerializer.Serialize(this, UnityInfoSerializerContext.WriteIndentedContext.UnityClass)
: JsonSerializer.Serialize(this, UnityInfoSerializerContext.WriteNotIndentedContext.UnityClass);
}
public static UnityClass? FromJsonString(string jsonString)
{
return JsonSerializer.Deserialize(jsonString, UnityInfoSerializerContextIndented.Default.UnityClass);
return JsonSerializer.Deserialize(jsonString, UnityInfoSerializerContext.Default.UnityClass);
}
}
}
+14 -21
View File
@@ -1,30 +1,23 @@
using System.Text.Json;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
namespace AssetRipper.Tpk.TypeTrees.Json
{
public sealed class UnityInfo
{
private string version = "";
private List<UnityString> strings = new();
private List<UnityClass> classes = new();
public string Version
{
get => version;
set => version = value ?? "";
}
[AllowNull]
public List<UnityString> Strings
{
get => strings;
set => strings = value ?? new();
}
get;
set => field = value ?? new();
} = new();
[AllowNull]
public List<UnityClass> Classes
{
get => classes;
set => classes = value ?? new();
}
get;
set => field = value ?? new();
} = new();
public static UnityInfo ReadFromJsonFile(string jsonPath)
{
@@ -35,18 +28,18 @@ namespace AssetRipper.Tpk.TypeTrees.Json
public string ToJsonString(bool indented = false)
{
return indented
? JsonSerializer.Serialize(this, UnityInfoSerializerContextIndented.Default.UnityInfo)
: JsonSerializer.Serialize(this, UnityInfoSerializerContextNotIndented.Default.UnityInfo);
? JsonSerializer.Serialize(this, UnityInfoSerializerContext.WriteIndentedContext.UnityInfo)
: JsonSerializer.Serialize(this, UnityInfoSerializerContext.WriteNotIndentedContext.UnityInfo);
}
public static UnityInfo? FromJsonString(string jsonString)
{
return JsonSerializer.Deserialize(jsonString, UnityInfoSerializerContextIndented.Default.UnityInfo);
return JsonSerializer.Deserialize(jsonString, UnityInfoSerializerContext.Default.UnityInfo);
}
public static UnityInfo? FromStream(Stream utf8JsonStream)
{
return JsonSerializer.Deserialize(utf8JsonStream, UnityInfoSerializerContextIndented.Default.UnityInfo);
return JsonSerializer.Deserialize(utf8JsonStream, UnityInfoSerializerContext.Default.UnityInfo);
}
}
}
@@ -0,0 +1,31 @@
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace AssetRipper.Tpk.TypeTrees.Json
{
[JsonSourceGenerationOptions(IndentCharacter = '\t', IndentSize = 1)]
[JsonSerializable(typeof(UnityInfo))]
internal sealed partial class UnityInfoSerializerContext : JsonSerializerContext
{
public static UnityInfoSerializerContext WriteIndentedContext { get; }
public static UnityInfoSerializerContext WriteNotIndentedContext { get; }
static UnityInfoSerializerContext()
{
JsonSerializerOptions WriteIndentedOptions = new(s_defaultOptions)
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
WriteIndentedContext = new UnityInfoSerializerContext(WriteIndentedOptions);
JsonSerializerOptions WriteNotIndentedOptions = new(s_defaultOptions)
{
WriteIndented = false,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
WriteNotIndentedContext = new UnityInfoSerializerContext(WriteNotIndentedOptions);
}
}
}
@@ -1,10 +0,0 @@
using System.Text.Json.Serialization;
namespace AssetRipper.Tpk.TypeTrees.Json
{
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(UnityInfo))]
internal sealed partial class UnityInfoSerializerContextIndented : JsonSerializerContext
{
}
}
@@ -1,10 +0,0 @@
using System.Text.Json.Serialization;
namespace AssetRipper.Tpk.TypeTrees.Json
{
[JsonSourceGenerationOptions(WriteIndented = false)]
[JsonSerializable(typeof(UnityInfo))]
internal sealed partial class UnityInfoSerializerContextNotIndented : JsonSerializerContext
{
}
}
+24 -29
View File
@@ -1,6 +1,7 @@
using AssetRipper.HashAlgorithms;
using System.Buffers;
using System.Buffers.Binary;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
@@ -9,39 +10,39 @@ namespace AssetRipper.Tpk.TypeTrees.Json
{
public sealed class UnityNode
{
public string TypeName { get => typeName; set => typeName = value ?? ""; }
[AllowNull]
public string TypeName { get; set => field = value ?? ""; } = "";
/// <summary>
/// The original type name as obtained from the json file
/// </summary>
[JsonIgnore]
[AllowNull]
public string OriginalTypeName
{
get => string.IsNullOrEmpty(originalTypeName) ? TypeName : originalTypeName;
set => originalTypeName = value ?? "";
}
public string Name { get => name; set => name = value ?? ""; }
[AllowNull]
public string Name { get; set => field = value ?? ""; } = "";
/// <summary>
/// The original name as obtained from the json file
/// </summary>
[JsonIgnore]
[AllowNull]
public string OriginalName
{
get => string.IsNullOrEmpty(originalName) ? Name : originalName;
set => originalName = value ?? "";
}
public byte Level { get; set; }
public int ByteSize { get; set; }
public int Index { get; set; }
public short Version { get; set; }
public byte TypeFlags { get; set; }
public uint MetaFlag { get; set; }
public List<UnityNode> SubNodes { get => subNodes; set => subNodes = value ?? new(); }
[AllowNull]
public List<UnityNode> SubNodes { get; set => field = value ?? []; } = [];
private string originalTypeName = "";
private string originalName = "";
private string typeName = "";
private string name = "";
private List<UnityNode> subNodes = new();
/// <summary>
/// Deep clones a node and all its subnodes<br/>
@@ -50,36 +51,30 @@ namespace AssetRipper.Tpk.TypeTrees.Json
/// <returns>The new node</returns>
public UnityNode DeepClone()
{
UnityNode cloned = new UnityNode();
cloned.TypeName = CloneString(TypeName);
cloned.originalTypeName = CloneString(originalTypeName);
cloned.Name = CloneString(Name);
cloned.originalName = CloneString(originalName);
cloned.Level = Level;
cloned.ByteSize = ByteSize;
cloned.Index = Index;
cloned.Version = Version;
cloned.TypeFlags = TypeFlags;
cloned.MetaFlag = MetaFlag;
cloned.SubNodes = SubNodes.ConvertAll(x => x.DeepClone());
return cloned;
}
private static string CloneString(string? @string)
{
return @string == null ? "" : new string(@string);
return new UnityNode
{
TypeName = TypeName,
originalTypeName = originalTypeName,
Name = Name,
originalName = originalName,
ByteSize = ByteSize,
Version = Version,
TypeFlags = TypeFlags,
MetaFlag = MetaFlag,
SubNodes = SubNodes.ConvertAll(x => x.DeepClone()),
};
}
public string ToJsonString(bool indented = false)
{
return indented
? JsonSerializer.Serialize(this, UnityInfoSerializerContextIndented.Default.UnityNode)
: JsonSerializer.Serialize(this, UnityInfoSerializerContextNotIndented.Default.UnityNode);
? JsonSerializer.Serialize(this, UnityInfoSerializerContext.WriteIndentedContext.UnityNode)
: JsonSerializer.Serialize(this, UnityInfoSerializerContext.WriteNotIndentedContext.UnityNode);
}
public static UnityNode? FromJsonString(string jsonString)
{
return JsonSerializer.Deserialize(jsonString, UnityInfoSerializerContextIndented.Default.UnityNode);
return JsonSerializer.Deserialize(jsonString, UnityInfoSerializerContext.Default.UnityNode);
}
/// <summary>
+9 -8
View File
@@ -1,24 +1,25 @@
using System.Text.Json;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
namespace AssetRipper.Tpk.TypeTrees.Json
{
public sealed class UnityString
public sealed record class UnityString
{
private string @string = "";
public uint Index { get; set; }
public string String { get => @string; set => @string = value ?? ""; }
[AllowNull]
public string String { get; set => field = value ?? ""; } = "";
public string ToJsonString(bool indented = false)
{
return indented
? JsonSerializer.Serialize(this, UnityInfoSerializerContextIndented.Default.UnityString)
: JsonSerializer.Serialize(this, UnityInfoSerializerContextNotIndented.Default.UnityString);
? JsonSerializer.Serialize(this, UnityInfoSerializerContext.WriteIndentedContext.UnityString)
: JsonSerializer.Serialize(this, UnityInfoSerializerContext.WriteNotIndentedContext.UnityString);
}
public static UnityString? FromJsonString(string jsonString)
{
return JsonSerializer.Deserialize(jsonString, UnityInfoSerializerContextIndented.Default.UnityString);
return JsonSerializer.Deserialize(jsonString, UnityInfoSerializerContext.Default.UnityString);
}
}
}
+2 -2
View File
@@ -17,11 +17,11 @@
<ItemGroup>
<PackageReference Include="AssetRipper.Primitives" Version="3.2.0" />
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.8" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.201">
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.301">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SharpCompress" Version="0.47.3" />
<PackageReference Include="SharpCompress" Version="0.49.1" />
</ItemGroup>
</Project>
+1 -1
View File
@@ -8,7 +8,7 @@
/// <summary>
/// Name : Blob
/// </summary>
public List<KeyValuePair<string, TpkDataBlob>> Blobs { get; } = new List<KeyValuePair<string, TpkDataBlob>>();
public List<KeyValuePair<string, TpkDataBlob>> Blobs { get; } = [];
public override TpkDataType DataType => TpkDataType.Collection;
+1 -1
View File
@@ -6,7 +6,7 @@ namespace AssetRipper.Tpk
public sealed class TpkFile
{
public const uint TpkMagicBytes = 0x2A4B5054; // TPK* in binary
public const byte TpkVersionNumber = 1;
public const byte TpkVersionNumber = 2;
public TpkCompressionType CompressionType { get; private set; }
public TpkDataType DataType { get; private set; }
+3 -1
View File
@@ -21,7 +21,9 @@ namespace AssetRipper.Tpk.TypeTrees
/// </summary>
public List<VersionClassPair> Classes { get; } = new();
public TpkClassInformation() { }
public TpkClassInformation()
{
}
public TpkClassInformation(int id)
{
+50 -45
View File
@@ -9,33 +9,51 @@ namespace AssetRipper.Tpk.TypeTrees
public sealed class TpkCommonString
{
/// <summary>
/// Unity version : string count<br/>
/// Sequential by ascending Unity version
/// An entry in <see cref="TpkCommonString"/>
/// </summary>
public List<KeyValuePair<UnityVersion, byte>> VersionInformation { get; } = new();
public List<ushort> StringBufferIndices { get; } = new();
public void Add(UnityVersion version, byte count)
/// <param name="Offset">The byte offset of the string</param>
/// <param name="String">The index of the string in <see cref="TpkStringBuffer"/></param>
public readonly record struct Entry(ushort Offset, ushort String)
{
VersionInformation.Add(new KeyValuePair<UnityVersion, byte>(version, count));
}
public void SetIndices(TpkStringBuffer buffer, List<string> strings)
{
int count = strings.Count;
StringBufferIndices.Clear();
StringBufferIndices.Capacity = count;
for (int i = 0; i < count; i++)
public Entry(ushort offset, string @string, TpkStringBuffer buffer) : this(offset, buffer.AddString(@string))
{
StringBufferIndices.Add(buffer.AddString(strings[i]));
}
public string ToString(TpkStringBuffer buffer)
{
return buffer[String];
}
public static Entry Read(BinaryReader reader)
{
ushort offset = reader.ReadUInt16();
ushort stringIndex = reader.ReadUInt16();
return new Entry(offset, stringIndex);
}
public void Write(BinaryWriter writer)
{
writer.Write(Offset);
writer.Write(String);
}
}
public byte GetCount(UnityVersion exactVersion)
/// <summary>
/// Unity version : string count<br/>
/// Sequential by ascending Unity version
/// </summary>
public List<KeyValuePair<UnityVersion, Entry[]>> VersionInformation { get; } = new();
public void Add(UnityVersion version, Entry[] entries)
{
VersionInformation.Add(new KeyValuePair<UnityVersion, Entry[]>(version, entries));
}
public Entry[] GetEntries(UnityVersion exactVersion)
{
if (VersionInformation.Count == 0)
{
return 0;
return [];
}
for (int i = 1; i < VersionInformation.Count; i++)
{
@@ -44,18 +62,7 @@ namespace AssetRipper.Tpk.TypeTrees
return VersionInformation[i - 1].Value;
}
}
return VersionInformation[VersionInformation.Count - 1].Value;
}
public string[] GetStrings(TpkStringBuffer buffer)
{
int length = StringBufferIndices.Count;
string[] strings = new string[length];
for (int i = 0; i < length; i++)
{
strings[i] = buffer[StringBufferIndices[i]];
}
return strings;
return VersionInformation[^1].Value;
}
public void Read(BinaryReader reader)
@@ -66,15 +73,13 @@ namespace AssetRipper.Tpk.TypeTrees
for (int i = 0; i < versionCount; i++)
{
UnityVersion version = reader.ReadUnityVersion();
byte stringCount = reader.ReadByte();
VersionInformation.Add(new KeyValuePair<UnityVersion, byte>(version, stringCount));
}
int indicesCount = reader.ReadInt32();
StringBufferIndices.Clear();
StringBufferIndices.Capacity = indicesCount;
for (int j = 0; j < indicesCount; j++)
{
StringBufferIndices.Add(reader.ReadUInt16());
int entryCount = reader.ReadInt32();
Entry[] entries = new Entry[entryCount];
for (int j = 0; j < entryCount; j++)
{
entries[j] = Entry.Read(reader);
}
VersionInformation.Add(new KeyValuePair<UnityVersion, Entry[]>(version, entries));
}
}
@@ -84,12 +89,12 @@ namespace AssetRipper.Tpk.TypeTrees
for (int i = 0; i < VersionInformation.Count; i++)
{
writer.Write(VersionInformation[i].Key);
writer.Write(VersionInformation[i].Value);
}
writer.Write(StringBufferIndices.Count);
for (int i = 0; i < StringBufferIndices.Count; i++)
{
writer.Write(StringBufferIndices[i]);
Entry[] entries = VersionInformation[i].Value;
writer.Write(entries.Length);
for (int j = 0; j < entries.Length; j++)
{
entries[j].Write(writer);
}
}
}
}
-2
View File
@@ -18,8 +18,6 @@
//Derived and Descendent count are excluded from this format
//Size and TypeIndex are excluded from this format
/// <summary>
/// 8 boolean values packed into 1 byte
/// </summary>
+2 -18
View File
@@ -4,13 +4,11 @@
{
public ushort TypeName { get; set; }
public ushort Name { get; set; }
//Level is redundant
public int ByteSize { get; set; }
//Index is redundant
public short Version { get; set; }
public byte TypeFlags { get; set; }
public uint MetaFlag { get; set; }
public ushort[] SubNodes { get; set; } = Array.Empty<ushort>();
public ushort[] SubNodes { get; set; } = [];
public void Read(BinaryReader reader)
{
@@ -62,21 +60,7 @@
Version == other.Version &&
TypeFlags == other.TypeFlags &&
MetaFlag == other.MetaFlag &&
ArrayEqual(SubNodes, other.SubNodes);
}
private static bool ArrayEqual(ushort[] array1, ushort[] array2)
{
if (array1.Length != array2.Length)
return false;
for (int i = 0; i < array1.Length; i++)
{
if (array1[i] != array2[i])
{
return false;
}
}
return true;
SubNodes.SequenceEqual(other.SubNodes);
}
}
}