15 Commits
Author SHA1 Message Date
ds5678 51873aaef9 Bump version 2024-08-28 21:27:29 -07:00
ds5678 a43a560f9a Use string instead of UnityGuid on NET Standard 2024-08-28 21:27:23 -07:00
ds5678 54eb41b856 EngineResourceData deserialization improvements 2024-08-15 21:49:21 -07:00
ds5678 2b22375c90 Improve Unity 2 and 3 support 2024-06-01 08:41:50 -07:00
ds5678 d989f9f16a Use SerializableValue indexer property 2024-05-31 20:36:45 -07:00
ds5678 19fb8b36dd Small name fix 2024-05-31 20:25:09 -07:00
aldelaro5 9479c1aa66 Init the aabb part of the mesh key (#3) 2024-05-31 20:09:41 -07:00
ds5678 5bb396ffda Make the internal serializer context public
* Add tests for Vector3 serialization and deserialization
* Bump AssetRipper.Primitives
2024-05-31 07:55:33 -07:00
ds5678 e014834c04 Bump version 2024-05-30 21:46:13 -07:00
ds5678 bf8806c154 Include fields for serialization 2024-05-30 21:44:21 -07:00
ds5678 40841a3c19 Bump AssetRipper.Mining.PredefinedAssets version 2024-05-30 21:22:58 -07:00
aldelaro5 a0fc1e8bc9 Add the AABB fields in the key of meshes (#2) 2024-05-30 21:19:22 -07:00
ds5678 5832762d66 Add reference assembly data 2024-05-30 21:04:58 -07:00
ds5678 cfcbb3e7ba More forgiving about MonoScript fields 2024-05-30 08:22:50 -07:00
ds5678 a3dfe6341b Switch from AssetsTools to the internal AssetRipper libaries 2024-05-30 00:33:42 -07:00
16 changed files with 236 additions and 548 deletions

No files matched your search

@@ -1,270 +0,0 @@
using AngleSharp;
using AngleSharp.Dom;
using AssetRipper.Primitives;
using System.Diagnostics;
using System.Formats.Tar;
using System.IO.Compression;
namespace AssetRipper.Mining.AssemblyNameCollector;
public readonly record struct AssemblyData(IReadOnlyList<string> Mono2, IReadOnlyList<string> Mono4, IReadOnlyList<string> Unity, IReadOnlyList<KeyValuePair<string, UnityGuid>> UnityExtensions)
{
public static AssemblyData FromFolder(string root)
{
IReadOnlyList<string> mono2 = GetAssemblies_Mono2(root);
IReadOnlyList<string> mono4 = GetAssemblies_Mono4(root);
IReadOnlyList<string> unity = GetAssemblies_Unity(root);
IReadOnlyList<KeyValuePair<string, UnityGuid>> unityExtensions = GetUnityExtensions(root).Concat(GetUnityPackages(root)).OrderBy(pair => pair.Key).ToList();
return new AssemblyData(mono2, mono4, unity, unityExtensions);
}
public bool Equals(AssemblyData other)
{
return Mono2.SequenceEqual(other.Mono2) && Mono4.SequenceEqual(other.Mono4) && Unity.SequenceEqual(other.Unity) && UnityExtensions.SequenceEqual(other.UnityExtensions);
}
public override int GetHashCode()
{
HashCode hash = new();
foreach (string assembly in Mono2)
{
hash.Add(assembly);
}
foreach (string assembly in Mono4)
{
hash.Add(assembly);
}
foreach (string assembly in Unity)
{
hash.Add(assembly);
}
foreach (KeyValuePair<string, UnityGuid> pair in UnityExtensions)
{
hash.Add(pair);
}
return hash.ToHashCode();
}
static IReadOnlyList<string> GetAssemblies_Mono2(string root)
{
return GetAssemblies(root,
"Editor/Data/Mono/lib/mono/unity",
"Editor/Data/Mono/lib/mono/2.0",
"Editor/Data/Frameworks/Mono.framework");
}
static IReadOnlyList<string> GetAssemblies_Mono4(string root)
{
return GetAssemblies(root,
"Editor/Data/MonoBleedingEdge/lib/mono/unityjit-win32",
"Editor/Data/MonoBleedingEdge/lib/mono/unityjit",
"Editor/Data/MonoBleedingEdge/lib/mono/unity",
"Editor/Data/MonoBleedingEdge/lib/mono/4.5",
"Editor/Data/MonoBleedingEdge/lib/mono/4.0");
}
static IReadOnlyList<string> GetAssemblies_Unity(string root)
{
if (Directory.Exists(Path.Combine(root, "Editor/Data/Frameworks")))
{
// Unity 2
return ["UnityEngine"];
}
return GetAssemblies(root,
"Editor/Data/PlaybackEngines/windowsstandalonesupport/Variations/win64_nondevelopment/Data/Managed",
"Editor/Data/PlaybackEngines/windowsstandalonesupport/Variations/win64_nondevelopment_mono/Data/Managed",
"Editor/Data/PlaybackEngines/windowsstandalonesupport/Variations/win64_player_nondevelopment_mono/Data/Managed",
"Editor/Data/PlaybackEngines/windows64standaloneplayer/Managed",
"Editor/Data/PlaybackEngines/windowsstandaloneplayer/Managed");
}
static IReadOnlyList<string> GetAssemblies(string root, params ReadOnlySpan<string> relativePaths)
{
foreach (string relativePath in relativePaths)
{
string path = Path.Combine(root, relativePath);
if (Directory.Exists(path))
{
List<string> result = GetManagedAssemblies(path).ToList();
string facadeDirectory = Path.Combine(path, "Facades");
if (Directory.Exists(facadeDirectory))
{
result.AddRange(GetManagedAssemblies(facadeDirectory).Where(a => !result.Contains(a)));
}
return result;
}
}
return [];
}
static IEnumerable<string> GetManagedAssemblies(string directory)
{
return Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories)
.Select(Path.GetFileNameWithoutExtension)
.Where(s => !string.IsNullOrEmpty(s))
.Distinct()
.Order()!;
}
static IReadOnlyList<KeyValuePair<string, UnityGuid>> GetUnityExtensions(string root)
{
string directory = Path.Combine(root, "Editor/Data/UnityExtensions");
if (Directory.Exists(directory))
{
List<(string, UnityGuid)> extractedArtifacts = new();
foreach (string file in Directory.EnumerateFiles(directory, "ivy.xml", SearchOption.AllDirectories))
{
string xml = File.ReadAllText(file);
IDocument document = BrowsingContext.New(Configuration.Default.WithXml()).OpenAsync(req => req.Content(xml)).GetAwaiter().GetResult();
foreach (IElement artifact in document.QuerySelectorAll("artifact"))
{
string? name = artifact.GetAttribute("name");
string? type = artifact.GetAttribute("type");
string? ext = artifact.GetAttribute("ext");
string? guidString = artifact.GetAttribute("e:guid"); // namespaced attribute
if (string.IsNullOrEmpty(name) || type is not "dll" || ext is not "dll" || string.IsNullOrEmpty(guidString) || !TryParseGuid(guidString, out UnityGuid guid))
{
continue;
}
extractedArtifacts.Add((name, guid));
}
}
Dictionary<string, List<(string, UnityGuid)>> dictionary = new();
foreach ((string path, UnityGuid guid) in extractedArtifacts)
{
string name = Path.GetFileName(path);
if (!dictionary.TryGetValue(name, out List<(string, UnityGuid)>? newList))
{
newList = new();
dictionary.Add(name, newList);
}
newList.Add((path, guid));
}
List<KeyValuePair<string, UnityGuid>> finalList = new();
foreach ((string name, List<(string, UnityGuid)> subList) in dictionary.OrderBy(p => p.Key))
{
Debug.Assert(subList.Count > 0);
UnityGuid guid;
if (subList.Count == 1)
{
guid = subList[0].Item2;
}
else
{
guid = subList.FirstOrDefault(pair => pair.Item1 == name).Item2;
if (guid != default)
{
goto Found;
}
ReadOnlySpan<string> starts =
[
"Standalone/", // Preferred over Editor/
"Runtime/", // Preferred over RuntimeEditor/
// NUnit
"portable/",
"nunit-standalone/",
];
foreach (string start in starts)
{
foreach ((string path, UnityGuid subGuid) in subList)
{
if (path.StartsWith(start, StringComparison.Ordinal))
{
guid = subGuid;
goto Found;
}
}
}
throw new InvalidOperationException($"Failed to find a guid for {name}");
}
Found:
finalList.Add(new(name, guid));
}
return finalList;
}
return [];
}
static IReadOnlyList<KeyValuePair<string, UnityGuid>> GetUnityPackages(string root)
{
// Unity 2017.2 introduced packages, which are stored in a compressed format.
if (root.EndsWith("2017.4.34f1", StringComparison.Ordinal))
{
// Unity 2017.4.34f1 uses a weird compression format for packages.
// It's the only version that does this, so we redirect to the subsequent version.
return GetUnityPackages(Path.Combine(Path.GetDirectoryName(root) ?? string.Empty, "2017.4.35f1"));
}
else if (!Path.GetFileName(root).StartsWith("2017.", StringComparison.Ordinal))
{
// Unity 2018.1 introduced the Package Manager UI, which makes package references no longer automatic.
return [];
}
string directory = Path.Combine(root, "Editor/Data/Resources/PackageManager/Editor");
if (!Directory.Exists(directory))
{
return [];
}
List<KeyValuePair<string, UnityGuid>> assemblyGuids = [];
foreach (string file in Directory.EnumerateFiles(directory, "*.tgz"))
{
using FileStream fileStream = File.OpenRead(file);
using GZipStream gzipStream = new(fileStream, CompressionMode.Decompress);
MemoryStream tarStream = new();
gzipStream.CopyTo(tarStream);
tarStream.Position = 0;
using TarReader reader = new(tarStream);
TarEntry? entry;
while ((entry = reader.GetNextEntry()) is not null)
{
string? entryPath = entry.Name;
if (string.IsNullOrEmpty(entryPath) || !entryPath.EndsWith(".dll.meta", StringComparison.Ordinal))
{
continue;
}
string assemblyName = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(entryPath)); // Remove .meta and .dll
string text = new StreamReader(entry.DataStream!).ReadToEnd();
string? guidString = text.Split('\n')
.FirstOrDefault(line => line.StartsWith("guid: ", StringComparison.Ordinal))?
.Substring("guid: ".Length)
.Trim();
if (!string.IsNullOrEmpty(guidString) && TryParseGuid(guidString, out UnityGuid guid))
{
assemblyGuids.Add(new KeyValuePair<string, UnityGuid>(assemblyName, guid));
}
}
}
return assemblyGuids;
}
private static bool TryParseGuid(string guidString, out UnityGuid guid)
{
// Todo: implement a proper solution upstream
try
{
guid = UnityGuid.Parse(guidString);
return true;
}
catch
{
guid = default;
return false;
}
}
}
@@ -1,13 +0,0 @@
using AssetRipper.Primitives;
using System.Text.Json;
namespace AssetRipper.Mining.AssemblyNameCollector;
public readonly record struct AssemblyDataFile(IReadOnlyList<UnityVersion> Versions, IReadOnlyList<KeyValuePair<UnityVersion, AssemblyData>> Assemblies)
{
public void Write(string path)
{
using FileStream stream = File.Create(path);
JsonSerializer.Serialize(stream, this, AssemblyDataSerializerContext.Default.AssemblyDataFile);
}
}
@@ -1,10 +0,0 @@
using AssetRipper.Primitives;
using System.Text.Json.Serialization;
namespace AssetRipper.Mining.AssemblyNameCollector;
[JsonSourceGenerationOptions(WriteIndented = true, IndentCharacter = '\t', IndentSize = 1, NewLine = "\n")]
[JsonSerializable(typeof(AssemblyDataFile))]
internal sealed partial class AssemblyDataSerializerContext : JsonSerializerContext
{
}
@@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AngleSharp" Version="1.3.0" />
<PackageReference Include="AngleSharp.Xml" Version="1.0.0" />
<PackageReference Include="AssetRipper.Primitives" Version="3.1.6" />
</ItemGroup>
</Project>
@@ -1,35 +0,0 @@
using AssetRipper.Primitives;
namespace AssetRipper.Mining.AssemblyNameCollector;
internal static class Program
{
static void Main(string[] args)
{
// Extract data
List<UnityVersion> versions = new();
List<KeyValuePair<UnityVersion, AssemblyData>> list = new();
foreach ((string directory, UnityVersion version) in GetRootDirectoriesInOrder(args[0]))
{
Console.WriteLine(directory);
versions.Add(version);
AssemblyData data = AssemblyData.FromFolder(directory);
if (list.Count is 0 || !list[^1].Value.Equals(data))
{
list.Add(new(version, data));
}
}
// Write data
new AssemblyDataFile(versions, list).Write(args[1]);
Console.WriteLine("Done!");
}
static IEnumerable<(string, UnityVersion)> GetRootDirectoriesInOrder(string parentDirectory)
{
return Directory.EnumerateDirectories(parentDirectory)
.Select(d => (d, UnityVersion.Parse(Path.GetFileName(d))))
.OrderBy(p => p.Item2);
}
}
@@ -2,17 +2,13 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AssetsTools.NET" Version="3.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AssetRipper.Mining.PredefinedAssets\AssetRipper.Mining.PredefinedAssets.csproj" />
<ProjectReference Include="..\..\AssetRipper\Source\AssetRipper.Import\AssetRipper.Import.csproj" />
</ItemGroup>
</Project>
@@ -1,24 +0,0 @@
using AssetRipper.Mining.PredefinedAssets;
using AssetsTools.NET;
using System.Numerics;
namespace AssetRipper.Mining.EngineFileExtractor;
internal static class AssetTypeValueFieldExtensions
{
public static AssetTypeValueField? TryGet(this AssetTypeValueField @this, string name)
{
AssetTypeValueField result = @this.Get(name);
return result.IsDummy ? null : result;
}
public static Vector3 AsVector3(this AssetTypeValueField @this)
{
return new Vector3(@this["x"].AsFloat, @this["y"].AsFloat, @this["z"].AsFloat);
}
public static AxisAlignedBoundingBox AsAxisAlignedBoundingBox(this AssetTypeValueField @this)
{
return new AxisAlignedBoundingBox(@this["m_Center"].AsVector3(), @this["m_Extent"].AsVector3());
}
}
+66 -110
View File
@@ -1,7 +1,15 @@
using AssetRipper.Mining.PredefinedAssets;
using AssetsTools.NET;
using AssetsTools.NET.Extra;
using System.Diagnostics;
using AssetRipper.Assets;
using AssetRipper.Assets.Bundles;
using AssetRipper.Assets.Collections;
using AssetRipper.Assets.Generics;
using AssetRipper.Assets.IO;
using AssetRipper.Assets.Metadata;
using AssetRipper.Import.AssetCreation;
using AssetRipper.Import.Structure.Assembly.Serializable;
using AssetRipper.Import.Structure.Assembly.TypeTrees;
using AssetRipper.IO.Endian;
using AssetRipper.IO.Files.SerializedFiles.Parser;
using AssetRipper.Mining.PredefinedAssets;
using Object = AssetRipper.Mining.PredefinedAssets.Object;
namespace AssetRipper.Mining.EngineFileExtractor;
@@ -40,32 +48,52 @@ internal static class Program
private static Dictionary<long, Object> ReadDictionary(string path)
{
if (!File.Exists(path))
{
return [];
}
return LoadAllAssetInfo(path).OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value);
}
private static IEnumerable<UnityAsset> LoadAllAssets(string path)
private static AssetCollection LoadAllAssets(string path)
{
AssetsManager manager = new();
AssetsFileInstance assetsFileInstance = manager.LoadAssetsFile(path, false);
foreach (AssetFileInfo assetFileInfo in assetsFileInstance.file.AssetInfos)
return GameBundle.FromPaths([path], TypeTreeAssetFactory.Instance).FetchAssetCollections().Single();
}
private sealed class TypeTreeAssetFactory : AssetFactoryBase
{
public static TypeTreeAssetFactory Instance { get; } = new();
public override IUnityObjectBase? ReadAsset(AssetInfo assetInfo, ReadOnlyArraySegment<byte> assetData, SerializedType? assetType)
{
yield return new UnityAsset(manager, assetsFileInstance, assetFileInfo);
ArgumentNullException.ThrowIfNull(assetType);
ArgumentOutOfRangeException.ThrowIfZero(assetType.OldType.Nodes.Count);
if (!TypeTreeNodeStruct.TryMakeFromTypeTree(assetType.OldType, out TypeTreeNodeStruct root))
{
throw new NotSupportedException("Type tree node struct creation failed");
}
else
{
TypeTreeObject asset = TypeTreeObject.Create(assetInfo, root);
EndianSpanReader reader = new(assetData, assetInfo.Collection.EndianType);
asset.Read(ref reader);
return asset;
}
}
}
private static IEnumerable<KeyValuePair<long, Object>> LoadAllAssetInfo(string path)
{
foreach (UnityAsset asset in LoadAllAssets(path))
foreach (TypeTreeObject asset in LoadAllAssets(path).Cast<TypeTreeObject>())
{
Object obj;
switch (asset.TypeID)
switch (asset.ClassID)
{
case 21://Material
{
obj = new Material()
{
Name = asset.Name,
Shader = asset.TryGetAsset("m_Shader")?.Name
Name = asset.Name(),
Shader = asset.TryGetAsset("m_Shader")?.Name()
};
}
break;
@@ -73,7 +101,7 @@ internal static class Program
{
obj = new Texture2D()
{
Name = asset.Name,
Name = asset.Name(),
Height = asset.GetInt32("m_Height"),
Width = asset.GetInt32("m_Width")
};
@@ -83,41 +111,43 @@ internal static class Program
{
obj = new Mesh()
{
Name = asset.Name,
VertexCount = asset.BaseField.Get("m_VertexData").Get("m_VertexCount").AsInt,
SubMeshCount = asset.BaseField.Get("m_SubMeshes").Get("Array").Children.Count,
LocalAABB = asset.BaseField.Get("m_LocalAABB").AsAxisAlignedBoundingBox(),
Name = asset.Name(),
VertexCount = asset.ReleaseFields.ContainsField("m_VertexData")
? asset.ReleaseFields["m_VertexData"]["m_VertexCount"].AsInt32
: asset.ReleaseFields["m_CompressedMesh"]["m_Vertices"]["m_NumItems"].AsInt32,
SubMeshCount = asset.ReleaseFields["m_SubMeshes"].AsAssetArray.Length,
LocalAABB = asset.ReleaseFields["m_LocalAABB"].AsAxisAlignedBoundingBox(),
};
}
break;
case 48://Shader
{
string[] propertyNames;
AssetTypeValueField serializedShader = asset.BaseField.Get("m_ParsedForm");
if (serializedShader.IsDummy)
SerializableStructure? serializedShader = asset.ReleaseFields.TryGetField("m_ParsedForm")?.AsStructure;
if (serializedShader is null)
{
propertyNames = Array.Empty<string>();
}
else
{
List<AssetTypeValueField> propsList = serializedShader.Get("m_PropInfo").Get("m_Props").Get("Array").Children;
if (propsList.Count == 0)
IUnityAssetBase[] propsList = serializedShader["m_PropInfo"]["m_Props"].AsAssetArray;
if (propsList.Length == 0)
{
propertyNames = Array.Empty<string>();
}
else
{
propertyNames = new string[propsList.Count];
for (int i = 0; i < propsList.Count; i++)
propertyNames = new string[propsList.Length];
for (int i = 0; i < propsList.Length; i++)
{
propertyNames[i] = propsList[i].Get("m_Name").AsString ?? "";
propertyNames[i] = ((SerializableStructure)propsList[i])["m_Name"].AsString;
}
}
}
obj = new Shader()
{
Name = asset.Name,
Name = asset.Name(),
PropertyNames = propertyNames
};
}
@@ -128,7 +158,7 @@ internal static class Program
{
obj = new Cubemap()
{
Name = asset.Name,
Name = asset.Name(),
Height = asset.GetInt32("m_Height"),
Width = asset.GetInt32("m_Width")
};
@@ -136,14 +166,14 @@ internal static class Program
break;
case 114://MonoBehaviour
{
UnityAsset? script = asset.TryGetAsset("m_Script");
TypeTreeObject? script = asset.TryGetAsset("m_Script");
obj = new MonoBehaviour()
{
Name = asset.Name,
AssemblyName = script?.GetString("m_AssemblyName") ?? "",
Name = asset.Name(),
AssemblyName = script?.TryGetString("m_AssemblyName") ?? "",
Namespace = script?.GetString("m_Namespace") ?? "",
ClassName = script?.GetString("m_ClassName") ?? "",
GameObject = asset.TryGetAsset("m_GameObject")?.Name,
GameObject = asset.TryGetAsset("m_GameObject")?.Name(),
Enabled = asset.GetBoolean("m_Enabled")
};
}
@@ -152,7 +182,7 @@ internal static class Program
{
obj = new MonoScript()
{
AssemblyName = asset.GetString("m_AssemblyName"),
AssemblyName = asset.TryGetString("m_AssemblyName") ?? "",
Namespace = asset.GetString("m_Namespace"),
ClassName = asset.GetString("m_ClassName")
};
@@ -164,8 +194,8 @@ internal static class Program
{
obj = new Sprite()
{
Name = asset.Name,
Texture = asset.ResolveAsset(asset.BaseField.Get("m_RD").Get("texture"))?.Name,
Name = asset.Name(),
Texture = asset.ResolveAsset(asset.ReleaseFields["m_RD"]["texture"].AsPPtr)?.Name(),
};
}
break;
@@ -174,86 +204,12 @@ internal static class Program
default:
obj = new GenericNamedObject()
{
TypeID = asset.TypeID,
Name = asset.Name
TypeID = asset.ClassID,
Name = asset.Name()
};
break;
}
yield return new KeyValuePair<long, Object>(asset.PathID, obj);
}
}
[DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)}(),nq}}")]
private readonly struct UnityAsset
{
private readonly AssetsManager manager;
private readonly AssetsFileInstance file;
private readonly AssetFileInfo info;
public UnityAsset(AssetsManager manager, AssetsFileInstance file, AssetFileInfo info)
{
this.manager = manager;
this.file = file;
this.info = info;
}
public int TypeID
{
get
{
int result = info.TypeId;
return result < 0 ? 114 : result;
}
}
public long PathID => info.PathId;
public string Name
{
get
{
AssetTypeValueField baseField = BaseField;
string? name = baseField.TryGet("m_Name")?.AsString;
if (string.IsNullOrEmpty(name) && TypeID == 48)//Shader
{
name = baseField.TryGet("m_ParsedForm")?.TryGet("m_Name")?.AsString //5.5 and later
?? baseField.TryGet("m_PathName")?.AsString; //Earlier than 5.5
if (string.IsNullOrEmpty(name)
&& (baseField.TryGet("m_Script")?.AsString?.StartsWith("Shader \"Standard\"", StringComparison.Ordinal) ?? false))
{
//A regex could be used to generalize, but as far as I know, Standard is the only one like this.
name = "Standard";
}
}
return name ?? "";
}
}
public string GetString(string fieldName) => BaseField.TryGet(fieldName)?.AsString ?? "";
public int GetInt32(string fieldName) => BaseField.Get(fieldName).AsInt;
public bool GetBoolean(string fieldName) => BaseField.Get(fieldName).AsBool;
public UnityAsset? TryGetAsset(string fieldName)
{
return ResolveAsset(BaseField.Get(fieldName));
}
public UnityAsset? ResolveAsset(AssetTypeValueField pptrField)
{
AssetExternal assetExternal = manager.GetExtAsset(file, pptrField);
return assetExternal.file is null || assetExternal.info is null
? null
: new UnityAsset(manager, assetExternal.file, assetExternal.info);
}
public AssetTypeValueField BaseField => manager.GetBaseField(file, info);
private string GetDebuggerDisplay()
{
return $"{TypeID} : {Name}";
}
}
}
@@ -0,0 +1,18 @@
using AssetRipper.Import.Structure.Assembly.Serializable;
using AssetRipper.Mining.PredefinedAssets;
using System.Numerics;
namespace AssetRipper.Mining.EngineFileExtractor;
internal static class SerializableValueExtensions
{
public static Vector3 AsVector3(this SerializableValue value)
{
return new Vector3(value["x"].AsSingle, value["y"].AsSingle, value["z"].AsSingle);
}
public static AxisAlignedBoundingBox AsAxisAlignedBoundingBox(this SerializableValue value)
{
return new AxisAlignedBoundingBox(value["m_Center"].AsVector3(), value["m_Extent"].AsVector3());
}
}
@@ -0,0 +1,59 @@
using AssetRipper.Assets.Metadata;
using AssetRipper.Import.AssetCreation;
using AssetRipper.Import.Structure.Assembly.Serializable;
namespace AssetRipper.Mining.EngineFileExtractor;
internal static class TypeTreeObjectExtensions
{
public static string Name(this TypeTreeObject asset)
{
SerializableStructure baseField = asset.ReleaseFields;
string? name = baseField.TryGetField("m_Name")?.AsString;
if (string.IsNullOrEmpty(name) && asset.ClassID == 48)//Shader
{
name = baseField.TryGetField("m_ParsedForm")?.AsStructure.TryGetField("m_Name")?.AsString //5.5 and later
?? baseField.TryGetField("m_PathName")?.AsString; //Earlier than 5.5
if (string.IsNullOrEmpty(name)
&& (baseField.TryGetField("m_Script")?.AsString?.StartsWith("Shader \"Standard\"", StringComparison.Ordinal) ?? false))
{
//A regex could be used to generalize, but as far as I know, Standard is the only one like this.
name = "Standard";
}
}
return name ?? "";
}
public static TypeTreeObject? TryGetAsset(this TypeTreeObject asset, string fieldName)
{
return asset.ReleaseFields.TryGetField(fieldName)?.AsAsset is IPPtr pptr
? asset.ResolveAsset(pptr)
: null;
}
public static bool GetBoolean(this TypeTreeObject asset, string fieldName)
{
return asset.ReleaseFields[fieldName].AsBoolean;
}
public static int GetInt32(this TypeTreeObject asset, string fieldName)
{
return asset.ReleaseFields[fieldName].AsInt32;
}
public static string GetString(this TypeTreeObject asset, string fieldName)
{
return asset.ReleaseFields[fieldName].AsString;
}
public static string? TryGetString(this TypeTreeObject asset, string fieldName)
{
return asset.ReleaseFields.TryGetField(fieldName)?.AsString;
}
public static TypeTreeObject? ResolveAsset(this TypeTreeObject asset, IPPtr pptr)
{
return asset.Collection.TryGetAsset(new PPtr<TypeTreeObject>(pptr.FileID, pptr.PathID));
}
}
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net4.8;net9.0</TargetFrameworks>
<TargetFrameworks>net4.8;net7.0;net8.0</TargetFrameworks>
<LangVersion>Latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
@@ -11,16 +11,16 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="NUnit" Version="4.3.2" />
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.7.0">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
<PackageReference Include="NUnit" Version="4.2.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
@@ -1,47 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>Latest</LangVersion>
<Nullable>enable</Nullable>
<IsAotCompatible Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">true</IsAotCompatible>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<Authors>ds5678</Authors>
<Company>AssetRipper</Company>
<Version>1.5.0</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<PackageId>AssetRipper.Mining.PredefinedAssets</PackageId>
<PackageTags>C# Unity</PackageTags>
<RepositoryUrl>https://github.com/AssetRipper/AssetRipper.Mining</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryType>git</RepositoryType>
<PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl>
<Copyright>Copyright (c) 2023 - 2025 ds5678</Copyright>
<Description>Library for storing datamined asset information.</Description>
<PackageReadmeFile>README.md</PackageReadmeFile>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AssetRipper.Primitives" Version="3.1.6" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="PolySharp" Version="1.15.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Text.Json" Version="9.0.4" />
</ItemGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net7.0;net8.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>Latest</LangVersion>
<Nullable>enable</Nullable>
<IsAotCompatible>true</IsAotCompatible>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<Authors>ds5678</Authors>
<Company>AssetRipper</Company>
<Version>1.4.0</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<PackageId>AssetRipper.Mining.PredefinedAssets</PackageId>
<PackageTags>C# Unity</PackageTags>
<RepositoryUrl>https://github.com/AssetRipper/AssetRipper.Mining</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryType>git</RepositoryType>
<PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl>
<Copyright>Copyright (c) 2023 - 2024 ds5678</Copyright>
<Description>Library for storing datamined asset information.</Description>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AssetRipper.Primitives" Version="3.1.3" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="PolySharp" Version="1.14.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Text.Json" Version="8.0.4" />
</ItemGroup>
</Project>
@@ -1,4 +1,6 @@
namespace AssetRipper.Mining.PredefinedAssets;
using System.Diagnostics.CodeAnalysis;
namespace AssetRipper.Mining.PredefinedAssets;
public sealed record class GameObject : Object
{
@@ -1 +0,0 @@
# AssetRipper.Mining.PredefinedAssets
@@ -1,4 +1,6 @@
namespace AssetRipper.Mining.PredefinedAssets;
using System.Diagnostics.CodeAnalysis;
namespace AssetRipper.Mining.PredefinedAssets;
public sealed record class Shader : NamedObject
{
+36 -6
View File
@@ -14,9 +14,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetRipper.Mining.Predefin
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetRipper.Mining.EngineFileExtractor", "AssetRipper.Mining.EngineFileExtractor\AssetRipper.Mining.EngineFileExtractor.csproj", "{DAD9BA2F-8A03-43D8-A3E5-73493A10AF0B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetRipper.Mining.PredefinedAssets.Tests", "AssetRipper.Mining.PredefinedAssets.Tests\AssetRipper.Mining.PredefinedAssets.Tests.csproj", "{C3E8E9EA-1710-4346-B96A-EA757FB13301}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetRipper.Mining.PredefinedAssets.Tests", "AssetRipper.Mining.PredefinedAssets.Tests\AssetRipper.Mining.PredefinedAssets.Tests.csproj", "{C3E8E9EA-1710-4346-B96A-EA757FB13301}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetRipper.Mining.AssemblyNameCollector", "AssetRipper.Mining.AssemblyNameCollector\AssetRipper.Mining.AssemblyNameCollector.csproj", "{90716FE5-A36D-4F2F-AC14-877BF63053E2}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetRipper.Import", "..\AssetRipper\Source\AssetRipper.Import\AssetRipper.Import.csproj", "{44876B0D-F234-46E7-9A94-BE35CA29049F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetRipper.SourceGenerated.Extensions", "..\AssetRipper\Source\AssetRipper.SourceGenerated.Extensions\AssetRipper.SourceGenerated.Extensions.csproj", "{B5094214-6FC3-4F55-B448-D83E114BC1BC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetRipper.Numerics", "..\AssetRipper\Source\AssetRipper.Numerics\AssetRipper.Numerics.csproj", "{BDE02D36-76D0-4A73-A30C-6CD015FA5A99}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetRipper.Assets", "..\AssetRipper\Source\AssetRipper.Assets\AssetRipper.Assets.csproj", "{98EE060B-FFE4-4D52-B361-69D42D2C00A4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetRipper.IO.Files", "..\AssetRipper\Source\AssetRipper.IO.Files\AssetRipper.IO.Files.csproj", "{6F14FBBA-B839-4023-8C92-138A57F30673}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetRipper.SerializationLogic", "..\AssetRipper\Source\AssetRipper.SerializationLogic\AssetRipper.SerializationLogic.csproj", "{A24296F8-A10F-43B5-8190-4406C75882D3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -36,10 +46,30 @@ Global
{C3E8E9EA-1710-4346-B96A-EA757FB13301}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3E8E9EA-1710-4346-B96A-EA757FB13301}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3E8E9EA-1710-4346-B96A-EA757FB13301}.Release|Any CPU.Build.0 = Release|Any CPU
{90716FE5-A36D-4F2F-AC14-877BF63053E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{90716FE5-A36D-4F2F-AC14-877BF63053E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{90716FE5-A36D-4F2F-AC14-877BF63053E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{90716FE5-A36D-4F2F-AC14-877BF63053E2}.Release|Any CPU.Build.0 = Release|Any CPU
{44876B0D-F234-46E7-9A94-BE35CA29049F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44876B0D-F234-46E7-9A94-BE35CA29049F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44876B0D-F234-46E7-9A94-BE35CA29049F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44876B0D-F234-46E7-9A94-BE35CA29049F}.Release|Any CPU.Build.0 = Release|Any CPU
{B5094214-6FC3-4F55-B448-D83E114BC1BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B5094214-6FC3-4F55-B448-D83E114BC1BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B5094214-6FC3-4F55-B448-D83E114BC1BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B5094214-6FC3-4F55-B448-D83E114BC1BC}.Release|Any CPU.Build.0 = Release|Any CPU
{BDE02D36-76D0-4A73-A30C-6CD015FA5A99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BDE02D36-76D0-4A73-A30C-6CD015FA5A99}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BDE02D36-76D0-4A73-A30C-6CD015FA5A99}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BDE02D36-76D0-4A73-A30C-6CD015FA5A99}.Release|Any CPU.Build.0 = Release|Any CPU
{98EE060B-FFE4-4D52-B361-69D42D2C00A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{98EE060B-FFE4-4D52-B361-69D42D2C00A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{98EE060B-FFE4-4D52-B361-69D42D2C00A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{98EE060B-FFE4-4D52-B361-69D42D2C00A4}.Release|Any CPU.Build.0 = Release|Any CPU
{6F14FBBA-B839-4023-8C92-138A57F30673}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6F14FBBA-B839-4023-8C92-138A57F30673}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6F14FBBA-B839-4023-8C92-138A57F30673}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6F14FBBA-B839-4023-8C92-138A57F30673}.Release|Any CPU.Build.0 = Release|Any CPU
{A24296F8-A10F-43B5-8190-4406C75882D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A24296F8-A10F-43B5-8190-4406C75882D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A24296F8-A10F-43B5-8190-4406C75882D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A24296F8-A10F-43B5-8190-4406C75882D3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE