mirror of
https://github.com/AssetRipper/AssetRipper.Mining.git
synced 2026-11-14 06:18:09 -10:00
Compare commits
15
Commits
assetstools
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51873aaef9 | ||
|
|
a43a560f9a | ||
|
|
54eb41b856 | ||
|
|
2b22375c90 | ||
|
|
d989f9f16a | ||
|
|
19fb8b36dd | ||
|
|
9479c1aa66 | ||
|
|
5bb396ffda | ||
|
|
e014834c04 | ||
|
|
bf8806c154 | ||
|
|
40841a3c19 | ||
|
|
a0fc1e8bc9 | ||
|
|
5832762d66 | ||
|
|
cfcbb3e7ba | ||
|
|
a3dfe6341b |
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
|
||||
{
|
||||
}
|
||||
-16
@@ -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
-6
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -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
@@ -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
|
||||
|
||||
Reference in new issue
Block a user