mirror of
https://github.com/AssetRipper/Tpk.git
synced 2026-11-13 18:07:47 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f94757d204 | ||
|
|
474fe30489 | ||
|
|
70c3b6ca93 | ||
|
|
6b72bf855d |
No files matched your search
@@ -9,7 +9,7 @@
|
||||
|
||||
<Authors>ds5678</Authors>
|
||||
<Company>AssetRipper</Company>
|
||||
<VersionPrefix>1.2.1</VersionPrefix>
|
||||
<VersionPrefix>2.0.0</VersionPrefix>
|
||||
<RepositoryUrl>https://github.com/AssetRipper/Tpk</RepositoryUrl>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using AssetRipper.Primitives;
|
||||
using AssetRipper.Tpk.Shared;
|
||||
using AssetRipper.Tpk.TypeTrees;
|
||||
using AssetRipper.Tpk.TypeTrees.Json;
|
||||
using System.Collections.Generic;
|
||||
@@ -40,37 +41,25 @@ namespace AssetRipper.Tpk.ConsoleApp
|
||||
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 ((UnityVersion version, UnityInfo? info) in infosOrderedByUnityVersion)
|
||||
{
|
||||
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)
|
||||
@@ -120,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");
|
||||
@@ -131,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;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using AssetRipper.Primitives;
|
||||
using AssetRipper.Tpk.TypeTrees;
|
||||
using NUnit.Framework;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetRipper.Tpk.Tests.TypeTrees
|
||||
{
|
||||
@@ -16,7 +17,7 @@ namespace AssetRipper.Tpk.Tests.TypeTrees
|
||||
public static void CountIsCorrectForEmptyCommonString()
|
||||
{
|
||||
TpkCommonString commonString = new();
|
||||
Assert.That(commonString.GetCount(Unity5), Is.Zero);
|
||||
Assert.That(commonString.GetEntries(Unity5), Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -25,19 +26,38 @@ namespace AssetRipper.Tpk.Tests.TypeTrees
|
||||
TpkCommonString commonString = MakeCommonString();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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; }
|
||||
|
||||
@@ -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++)
|
||||
{
|
||||
@@ -47,17 +65,6 @@ namespace AssetRipper.Tpk.TypeTrees
|
||||
return VersionInformation[^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;
|
||||
}
|
||||
|
||||
public void Read(BinaryReader reader)
|
||||
{
|
||||
int versionCount = reader.ReadInt32();
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user