Skip to content

Commit d681dcb

Browse files
committed
feat(TypeTreeGenerator): implement TypeTreeGenerator_AssetsTools
1 parent 92615db commit d681dcb

2 files changed

Lines changed: 166 additions & 1 deletion

File tree

TypeTreeGeneratorAPI/TypeTreeGeneratorAPI.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
</PropertyGroup>
1111

1212
<ItemGroup>
13-
<PackageReference Include="AssetRipper.Primitives" Version="3.1.3" />
13+
<PackageReference Include="AssetRipper.Primitives" Version="3.2.0" />
14+
<PackageReference Include="AssetsTools.NET.MonoCecil" Version="1.0.1" />
1415
<PackageReference Include="Mono.Cecil" Version="0.11.6" />
1516
<PackageReference Include="Samboy063.Cpp2IL.Core" Version="2022.1.0-pre-release.19" />
1617
<PackageReference Include="System.Text.Json" Version="9.0.2" />
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
// credit: https://github.com/AhmedAhmedEG/Unity-Type-Tree-Generator/blob/main/UnityTypeTreeGeneratorCLI/CLI.cs
2+
// changes:
3+
// - assemblyMap -> monoTemplateFieldsGenerator.loadedAssemblies
4+
// - collpase GenerateTypeTreeNode into TypeTemplateToTypeTreeNodes
5+
using AssetsTools.NET;
6+
using AssetsTools.NET.Extra;
7+
using Mono.Cecil;
8+
using TypeTreeNode = AssetStudio.TypeTreeNode;
9+
10+
namespace TypeTreeGeneratorAPI
11+
{
12+
internal class TypeTreeGenerator_AssetsTools : TypeTreeGenerator
13+
{
14+
private readonly UnityVersion unityVersionExtra;
15+
private readonly MonoCecilTempGenerator monoTemplateFieldsGenerator = new("");
16+
private ClassDatabaseFile classDatabase = new();
17+
18+
public TypeTreeGenerator_AssetsTools(string unityVersion) : base(unityVersion)
19+
{
20+
unityVersionExtra = new UnityVersion(unityVersionString);
21+
}
22+
23+
~TypeTreeGenerator_AssetsTools()
24+
{
25+
monoTemplateFieldsGenerator.Dispose();
26+
}
27+
28+
public void InitClassDatabase(Stream stream)
29+
{
30+
var classPackage = new ClassPackageFile();
31+
classPackage.Read(new AssetsFileReader(stream));
32+
33+
classDatabase = classPackage.GetClassDatabase(this.unityVersionString);
34+
}
35+
36+
public override List<TypeTreeNode>? GenerateTreeNodes(string assemblyName, string fullName)
37+
{
38+
var asm = monoTemplateFieldsGenerator.loadedAssemblies[assemblyName];
39+
var type = asm.MainModule.Types.First(t => t.Name == fullName);
40+
41+
var typeTemplates = GenerateTypeTemplates(asm, type);
42+
if (typeTemplates.Any())
43+
{
44+
return GenerateTypeTreeNodes(typeTemplates);
45+
}
46+
return null;
47+
}
48+
49+
public override List<Tuple<string, string>> GetMonoBehaviourDefinitions()
50+
{
51+
var monoBehaviourDefs = new List<Tuple<string, string>>();
52+
foreach (var (asmName, asmDef) in monoTemplateFieldsGenerator.loadedAssemblies)
53+
{
54+
foreach (var type in asmDef.MainModule.Types)
55+
{
56+
if (IsMonoBehaviour(type))
57+
{
58+
monoBehaviourDefs.Add(new Tuple<string, string>(asmName, type.FullName));
59+
}
60+
}
61+
}
62+
return monoBehaviourDefs;
63+
}
64+
65+
public override void LoadDLL(Stream dllStream)
66+
{
67+
var assembly = AssemblyDefinition.ReadAssembly(dllStream, readerParameters);
68+
resolver.Register(assembly);
69+
monoTemplateFieldsGenerator.loadedAssemblies.Add(assembly.MainModule.Name, assembly);
70+
}
71+
72+
73+
74+
/* Returns a template field for a given type using the class database, It's essential for unity base types
75+
like MonoBehavior and GameObject, MonoCecilTempGenerator will never return template fields for unity base types. */
76+
private AssetTypeTemplateField? QueryClassDatabase(TypeDefinition type)
77+
{
78+
var typeTemplate = new AssetTypeTemplateField();
79+
var classDatabaseType = classDatabase.FindAssetClassByName(type.Name);
80+
81+
if (classDatabaseType is null || (classDatabaseType.EditorRootNode == null && classDatabaseType.ReleaseRootNode == null)) return null;
82+
typeTemplate.FromClassDatabase(classDatabase, classDatabaseType);
83+
84+
return typeTemplate;
85+
}
86+
87+
88+
/* Returns a list of type templates for a given type utilizing the class database for unity base types, and
89+
MonoCecilTempGenerator for the type it self, it returns an empty list if there was no type templates returned
90+
from any of the unity base types. */
91+
private List<AssetTypeTemplateField> GenerateTypeTemplates(AssemblyDefinition asm, TypeDefinition type)
92+
{
93+
var typeTemplates = new List<AssetTypeTemplateField>();
94+
var generatorTypeTemplates = monoTemplateFieldsGenerator.Read(asm,
95+
type.Namespace,
96+
type.Name,
97+
this.unityVersionExtra);
98+
99+
// If the generator resulted in nothing, this means this type is not serializable in the first place, so ignore it.
100+
if (generatorTypeTemplates.Count == 0) return typeTemplates;
101+
102+
var baseTypes = GetBaseTypes(type);
103+
foreach (var typeTemplate in baseTypes.Select(QueryClassDatabase))
104+
{
105+
// template fields of type component are not needed for deserialization.
106+
if (typeTemplate is null || typeTemplate.Type == "Component") continue;
107+
typeTemplates.Add(typeTemplate);
108+
109+
/* If the current template field type was one of those, then break as the generator recursively gets the
110+
rest of the base types internally, thus we prevent possible duplicates */
111+
if (typeTemplate.Type is "MonoBehaviour" or "ScriptableObject")
112+
break;
113+
}
114+
115+
/* If there's not a single type template for any of the base types, it means this type is not supported, thus,
116+
do not generate type templates for the type it self and return an empty list. */
117+
if (!typeTemplates.Any()) return typeTemplates;
118+
119+
typeTemplates.AddRange(generatorTypeTemplates);
120+
return typeTemplates;
121+
}
122+
123+
// Returns a list of type tree nodes given a list of type templates.
124+
private static List<TypeTreeNode> GenerateTypeTreeNodes(List<AssetTypeTemplateField> typeTemplates)
125+
{
126+
var typeTreeNodes = new List<TypeTreeNode>();
127+
if (!typeTemplates.Any()) return typeTreeNodes;
128+
129+
typeTreeNodes.AddRange(TypeTemplateToTypeTreeNodes(typeTemplates[0], level: 0));
130+
131+
for (int i = 1; i < typeTemplates.Count; i++)
132+
typeTreeNodes.AddRange(TypeTemplateToTypeTreeNodes(typeTemplates[i], level: 1));
133+
134+
return typeTreeNodes;
135+
}
136+
137+
// Recursive function that returns a list of type tree nodes for a type template including it's child type templates too.
138+
private static List<TypeTreeNode> TypeTemplateToTypeTreeNodes(AssetTypeTemplateField typeTemplate, int level = 0)
139+
{
140+
var typeTreeNodes = new List<TypeTreeNode> {
141+
new TypeTreeNode(typeTemplate.Type, typeTemplate.Name, level, typeTemplate.IsAligned)
142+
};
143+
144+
foreach (var child in typeTemplate.Children)
145+
typeTreeNodes.AddRange(TypeTemplateToTypeTreeNodes(child, level + 1));
146+
147+
return typeTreeNodes;
148+
}
149+
150+
// Returns a list of the base types for a given type, ordered from top type to bottom type.
151+
private static List<TypeDefinition> GetBaseTypes(TypeDefinition type)
152+
{
153+
var baseTypes = new List<TypeDefinition>();
154+
if (type.BaseType is null) return baseTypes;
155+
156+
var baseType = type.BaseType.Resolve();
157+
158+
baseTypes.Insert(0, baseType);
159+
baseTypes.InsertRange(0, GetBaseTypes(baseType));
160+
161+
return baseTypes;
162+
}
163+
}
164+
}

0 commit comments

Comments
 (0)