mirror of
https://github.com/AssetRipper/AssetRipper.Mining.git
synced 2026-11-14 06:18:09 -10:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82d9e144fd | ||
|
|
9ca9112942 | ||
|
|
8e0f803787 | ||
|
|
f01470f867 | ||
|
|
ab8b136b19 | ||
|
|
e9b0003601 | ||
|
|
9e2097dd81 |
No files matched your search
@@ -17,4 +17,27 @@ public class Tests
|
||||
}
|
||||
""".Replace(Environment.NewLine, "\n")));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UnityPackageDataCanBeSerialized()
|
||||
{
|
||||
UnityPackageData package = new UnityPackageData("Example", "1.0.0", true);
|
||||
package.Assets.Add(new TextAsset("", ""u8), default);
|
||||
string json = package.ToJson();
|
||||
Assert.That(json, Is.Not.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UnityPackageDataCanBeDeserialized()
|
||||
{
|
||||
UnityPackageData package = UnityPackageData.FromJson(MakeJson());
|
||||
Assert.That(package.Assets, Is.Not.Empty);
|
||||
|
||||
static string MakeJson()
|
||||
{
|
||||
UnityPackageData package = new UnityPackageData("Example", "1.0.0", true);
|
||||
package.Assets.Add(new TextAsset("", ""u8), default);
|
||||
return package.ToJson();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using AssetRipper.Primitives;
|
||||
using System.Collections;
|
||||
|
||||
namespace AssetRipper.Mining.PredefinedAssets;
|
||||
|
||||
public readonly struct AssetDictionary : IReadOnlyCollection<KeyValuePair<Object, PPtr>>, ICollection<KeyValuePair<Object, PPtr>>
|
||||
{
|
||||
//This class implements all the IReadOnlyDictionary`2 members, but does not implement the interface because that changes how System.Text.Json serializes it.
|
||||
|
||||
private readonly Dictionary<Object, PPtr> _dictionary = new();
|
||||
|
||||
public int Count => _dictionary.Count;
|
||||
|
||||
public IEnumerable<Object> Keys => _dictionary.Keys;
|
||||
|
||||
public IEnumerable<PPtr> Values => _dictionary.Values;
|
||||
|
||||
public PPtr this[Object key] => _dictionary[key];
|
||||
|
||||
public AssetDictionary()
|
||||
{
|
||||
}
|
||||
|
||||
public void Add(Object key, PPtr value) => _dictionary.Add(key, value);
|
||||
|
||||
public void Add(MonoScript key, UnityGuid guid) => Add(key, new PPtr(11500000, guid, AssetType.Meta));
|
||||
|
||||
public void Clear() => _dictionary.Clear();
|
||||
|
||||
public bool ContainsKey(Object key)
|
||||
{
|
||||
return _dictionary.ContainsKey(key);
|
||||
}
|
||||
|
||||
public bool TryAdd(Object key, PPtr value)
|
||||
{
|
||||
#if NETSTANDARD
|
||||
if (_dictionary.ContainsKey(key))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dictionary.Add(key, value);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
return _dictionary.TryAdd(key, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
public bool TryGetValue(Object key, out PPtr value)
|
||||
{
|
||||
return _dictionary.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<Object, PPtr>> GetEnumerator() => _dictionary.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
bool ICollection<KeyValuePair<Object, PPtr>>.IsReadOnly => ((ICollection<KeyValuePair<Object, PPtr>>)_dictionary).IsReadOnly;
|
||||
|
||||
void ICollection<KeyValuePair<Object, PPtr>>.Add(KeyValuePair<Object, PPtr> item)
|
||||
{
|
||||
((ICollection<KeyValuePair<Object, PPtr>>)_dictionary).Add(item);
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<Object, PPtr>>.Contains(KeyValuePair<Object, PPtr> item)
|
||||
{
|
||||
return ((ICollection<KeyValuePair<Object, PPtr>>)_dictionary).Contains(item);
|
||||
}
|
||||
|
||||
void ICollection<KeyValuePair<Object, PPtr>>.CopyTo(KeyValuePair<Object, PPtr>[] array, int arrayIndex)
|
||||
{
|
||||
((ICollection<KeyValuePair<Object, PPtr>>)_dictionary).CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<Object, PPtr>>.Remove(KeyValuePair<Object, PPtr> item)
|
||||
{
|
||||
return ((ICollection<KeyValuePair<Object, PPtr>>)_dictionary).Remove(item);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<Authors>ds5678</Authors>
|
||||
<Company>AssetRipper</Company>
|
||||
<Version>1.1.1</Version>
|
||||
<Version>1.2.1</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<PackageId>AssetRipper.Mining.PredefinedAssets</PackageId>
|
||||
<PackageTags>C# Unity</PackageTags>
|
||||
|
||||
@@ -17,4 +17,9 @@ public sealed record class MonoScript : Object
|
||||
Namespace = @namespace;
|
||||
ClassName = className;
|
||||
}
|
||||
|
||||
public static MonoScript FromType(Type type)
|
||||
{
|
||||
return new MonoScript(type.Assembly.GetName().Name, type.Namespace, type.Name);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,9 @@
|
||||
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(UInt128))]
|
||||
#else
|
||||
using AssetRipper.Mining.PredefinedAssets;
|
||||
using System.Buffers;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace System;
|
||||
@@ -35,6 +37,15 @@ public readonly record struct UInt128
|
||||
return TryParse(value, out UInt128 result) ? result : throw new FormatException("Input string was not in a correct format.");
|
||||
}
|
||||
|
||||
internal static UInt128 Parse(ReadOnlySpan<byte> value)
|
||||
{
|
||||
byte[] rented = ArrayPool<byte>.Shared.Rent(value.Length);
|
||||
value.CopyTo(rented);
|
||||
UInt128 result = Parse(Encoding.ASCII.GetString(rented, 0, value.Length));
|
||||
ArrayPool<byte>.Shared.Return(rented);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool TryParse(string value, out UInt128 result)
|
||||
{
|
||||
if (BigInteger.TryParse(value, out BigInteger bigInteger))
|
||||
@@ -57,8 +68,10 @@ public readonly record struct UInt128
|
||||
private static UInt128 FromBigInteger(BigInteger value)
|
||||
{
|
||||
ulong upper = (ulong)(value >> 64);
|
||||
ulong lower = (ulong)value;
|
||||
ulong lower = (ulong)(value & LowerBitMask);
|
||||
return new UInt128(upper, lower);
|
||||
}
|
||||
|
||||
private static readonly BigInteger LowerBitMask = new BigInteger(ulong.MaxValue);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -8,7 +8,7 @@ public sealed class UInt128JsonConverter : JsonConverter<UInt128>
|
||||
{
|
||||
public override UInt128 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
return UInt128.Parse(reader.GetString() ?? throw new JsonException("String was read as null"));
|
||||
return UInt128.Parse(reader.ValueSpan);
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, UInt128 value, JsonSerializerOptions options)
|
||||
@@ -16,4 +16,4 @@ public sealed class UInt128JsonConverter : JsonConverter<UInt128>
|
||||
writer.WriteRawValue(value.ToString());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,4 +1,5 @@
|
||||
using AssetRipper.Primitives;
|
||||
using System.Collections;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace AssetRipper.Mining.PredefinedAssets;
|
||||
@@ -13,19 +14,15 @@ namespace AssetRipper.Mining.PredefinedAssets;
|
||||
/// <param name="Version">The version or git url of this Unity package. Only applicable if <paramref name="UsedInPackageJson"/> is true.</param>
|
||||
/// <param name="UsedInPackageJson">If true, this Unity package should be referenced in the project's package json file.</param>
|
||||
/// <param name="Assemblies">A dictionary of compiled dll assemblies in the package.</param>
|
||||
/// <param name="Scripts">A dictionary of loose cs scripts in the package. Assembly name : { Full name : Guid }</param>
|
||||
/// <param name="Assets">A dictionary of assets in the package.</param>
|
||||
public readonly record struct UnityPackageData(
|
||||
string Name,
|
||||
string Version,
|
||||
bool UsedInPackageJson,
|
||||
Dictionary<string, UnityGuid> Assemblies,
|
||||
Dictionary<string, Dictionary<string, UnityGuid>> Scripts,
|
||||
List<KeyValuePair<Object, PPtr>> Assets)
|
||||
AssetDictionary Assets)
|
||||
{
|
||||
//Assets is a list because dictionaries require simple types as keys for serialization.
|
||||
|
||||
public UnityPackageData(string name, string version, bool usedInPackageJson) : this(name, version, usedInPackageJson, new(), new(), new())
|
||||
public UnityPackageData(string name, string version, bool usedInPackageJson) : this(name, version, usedInPackageJson, new(), new())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.0-preview.6.23329.7" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,6 @@
|
||||
using AssetRipper.Mining.Unity.Documentation.Web;
|
||||
|
||||
TocNode root = TocNode.FromJsonFile(@"toc.json") ?? throw new NullReferenceException();
|
||||
Dictionary<string, string> dictionary = TocAnalyzer.Analyze(root);
|
||||
Dictionary<string, string> reverseDictionary = dictionary.OrderBy(pair => pair.Value).ToDictionary(pair => pair.Value, pair => pair.Key);
|
||||
_ = reverseDictionary;
|
||||
@@ -0,0 +1,69 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace AssetRipper.Mining.Unity.Documentation.Web;
|
||||
public static class TocAnalyzer
|
||||
{
|
||||
public static Dictionary<string, string> Analyze(TocNode root)
|
||||
{
|
||||
Debug.Assert(root.IsRoot);
|
||||
Debug.Assert(root.HasChildren);
|
||||
|
||||
//Link : Full name
|
||||
Dictionary<string, string> result = new();
|
||||
Stack<(TocNode, int)> stack = new();
|
||||
foreach (TocNode rootChild in root.Children)
|
||||
{
|
||||
if (rootChild.Title is "Other")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
stack.Push((rootChild, -1));
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
(TocNode node, int childIndex) = stack.Pop();
|
||||
if (childIndex == -1)
|
||||
{
|
||||
if (node.IsType)
|
||||
{
|
||||
string @namespace = GetNamespace(stack, result);
|
||||
string fullName = $"{@namespace}.{node.Title}";
|
||||
result.Add(node.Link, fullName);
|
||||
}
|
||||
if (node.HasChildren && !node.IsAssemblyCollection)
|
||||
{
|
||||
stack.Push((node, 0));
|
||||
}
|
||||
}
|
||||
else if (childIndex < node.Children!.Length)
|
||||
{
|
||||
stack.Push((node, childIndex + 1));
|
||||
stack.Push((node.Children[childIndex], -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string GetNamespace(Stack<(TocNode, int)> stack, Dictionary<string, string> dictionary)
|
||||
{
|
||||
foreach ((TocNode node, _) in stack)
|
||||
{
|
||||
if (node.IsNamespace)
|
||||
{
|
||||
return node.Title;
|
||||
}
|
||||
if (node.IsType)
|
||||
{
|
||||
return dictionary[node.Link];
|
||||
}
|
||||
}
|
||||
if (stack.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("The stack is empty.");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Could not determine the namespace from the stack.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AssetRipper.Mining.Unity.Documentation.Web;
|
||||
|
||||
[DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)}(),nq}}")]
|
||||
public sealed class TocNode
|
||||
{
|
||||
private const string TOC = "toc";
|
||||
private const string Classes = "Classes";
|
||||
private const string Interfaces = "Interfaces";
|
||||
private const string Enumerations = "Enumerations";
|
||||
private const string Attributes = "Attributes";
|
||||
private const string Assemblies = "Assemblies";
|
||||
private string? link;
|
||||
|
||||
[JsonPropertyName("link")]
|
||||
public required string? Link
|
||||
{
|
||||
get => link;
|
||||
init
|
||||
{
|
||||
link = value is "null" ? null : value;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public required string Title { get; init; }
|
||||
|
||||
[JsonPropertyName("children")]
|
||||
public required TocNode[]? Children { get; init; }
|
||||
|
||||
[JsonIgnore]
|
||||
[MemberNotNullWhen(true, nameof(Link))]
|
||||
public bool IsRoot => Link is TOC && Title is TOC;
|
||||
|
||||
[JsonIgnore]
|
||||
[MemberNotNullWhen(true, nameof(Link))]
|
||||
public bool IsType => Link is not null and not TOC;
|
||||
|
||||
[JsonIgnore]
|
||||
[MemberNotNullWhen(false, nameof(Link))]
|
||||
public bool IsTypeCollection => Link is null && Title is Classes or Interfaces or Enumerations or Attributes;
|
||||
|
||||
[JsonIgnore]
|
||||
[MemberNotNullWhen(false, nameof(Link))]
|
||||
public bool IsAssemblyCollection => Link is null && Title is Assemblies;
|
||||
|
||||
[JsonIgnore]
|
||||
[MemberNotNullWhen(false, nameof(Link))]
|
||||
public bool IsNamespace => Link is null && Title is not Classes and not Interfaces and not Enumerations and not Attributes and not Assemblies;
|
||||
|
||||
[JsonIgnore]
|
||||
[MemberNotNullWhen(true, nameof(Children))]
|
||||
public bool HasChildren => Children is not null && Children.Length > 0;
|
||||
|
||||
public static TocNode? FromJsonText(string json)
|
||||
{
|
||||
return JsonSerializer.Deserialize(json, TocSerializerContext.Default.TocNode);
|
||||
}
|
||||
|
||||
public static TocNode? FromJsonFile(string path)
|
||||
{
|
||||
return JsonSerializer.Deserialize(File.OpenRead(path), TocSerializerContext.Default.TocNode);
|
||||
}
|
||||
|
||||
private string GetDebuggerDisplay()
|
||||
{
|
||||
return Title;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AssetRipper.Mining.Unity.Documentation.Web;
|
||||
|
||||
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
|
||||
[JsonSerializable(typeof(TocNode))]
|
||||
internal partial class TocSerializerContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
Reference in new issue
Block a user