Skip to content

Commit 8514d4b

Browse files
committed
Don't care about nested types
1 parent c7811c6 commit 8514d4b

File tree

3 files changed

+65
-54
lines changed

3 files changed

+65
-54
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ __pycache__/
44
*.egg-info
55
dump
66
generated/
7-
.DS_Store
7+
.DS_Store
8+
.temp
9+
.typetree.json

.vscode/launch.json

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,36 @@
66
"configurations": [
77

88
{
9-
"name": "Python Debugger: Module",
9+
"name": "Python Debugger: Sekai 5.5.0 JP",
1010
"type": "debugpy",
1111
"request": "launch",
1212
"module": "UnityPyTypetreeCodegen",
1313
"args": [
1414
"--il2cpp",
15-
"D:\\Reverse\\proseka_reverse\\UntitledCharts\\scripts\\.temp\\typetree\\libil2cpp.so",
15+
"C:\\Users\\mos9527\\UntitledCharts\\scripts\\.temp\\dump\\libil2cpp.so",
1616
"--metadata",
17-
"D:\\Reverse\\proseka_reverse\\UntitledCharts\\scripts\\.temp\\typetree\\global-metadata.dat"
17+
"C:\\Users\\mos9527\\UntitledCharts\\scripts\\.temp\\dump\\global-metadata.dat"
1818
]
19-
}
19+
},
20+
{
21+
"name": "Python Debugger: Live2D demo",
22+
"type": "debugpy",
23+
"request": "launch",
24+
"module": "UnityPyTypetreeCodegen",
25+
"args": [
26+
"--asm-dir",
27+
".temp\\dummy"
28+
]
29+
},
30+
{
31+
"name": "Python Debugger: JSON",
32+
"type": "debugpy",
33+
"request": "launch",
34+
"module": "UnityPyTypetreeCodegen",
35+
"args": [
36+
"--json",
37+
".typetree.json"
38+
]
39+
},
2040
]
2141
}

UnityPyTypetreeCodegen/__main__.py

Lines changed: 38 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"string": "str",
4343
"TypelessData": "bytes",
4444
# -- Extra
45+
"Array": "List[object]",
4546
"Byte[]": "bytes",
4647
"Byte": "int",
4748
"String": "str",
@@ -264,7 +265,7 @@ def declare_field(name: str, type: str, org_type: str = None):
264265
def topsort(graph: dict):
265266
# Sort the keys in topological order
266267
# We don't assume the guarantee otherwise
267-
graph = {k: list(sorted(v)) for k, v in graph.items()}
268+
graph = {k: list(sorted((i for i in v if i != k))) for k, v in graph.items()}
268269
vis = defaultdict(lambda: 0)
269270
topo = list()
270271

@@ -325,7 +326,6 @@ def emit_line(*lines: str):
325326
clazzes = list()
326327

327328
logger.info(f"Subpass 2: Generating code for {namespace}")
328-
dp = defaultdict(lambda: -1)
329329
for clazz in topo:
330330
fullname = f"{namespace}.{clazz}" if namespace else clazz
331331
fields = classname_nodes.get(clazz, None)
@@ -334,8 +334,6 @@ def emit_line(*lines: str):
334334
f"Class {clazz} has no fields defined in TypeTree dump, skipped"
335335
)
336336
continue
337-
# Heuristic: If there is a lvl1 field, it's a subclass
338-
lvl1 = list(filter(lambda field: field.m_Level == 1, fields))
339337
clazz = translate_name(clazz)
340338
clazzes.append(clazz)
341339
clazz_fields = list()
@@ -347,42 +345,20 @@ def __encoder(obj):
347345

348346
clazz_typetree = json.dumps(fields, default=__encoder)
349347
emit_line(f"@UTTCGen('{fullname}', {clazz_typetree})")
350-
if lvl1:
351-
parent = translate_type(fields[0].m_Type, strip=True, fallback=False)
352-
emit_line(f"class {translate_name(clazz)}({translate_name(parent)}):")
353-
if dp[parent] == -1:
354-
# Reuse parent's fields with best possible effort
355-
if pa_dep1 := getattr(UnityBuiltin, parent, None):
356-
dp[parent] = len(pa_dep1.__annotations__)
357-
else:
358-
raise ValueError # XXX: Should NEVER happen
359-
pa_dep1 = dp[parent]
360-
cur_dep1 = pa_dep1
361-
for dep, (i, field) in enumerate(
362-
filter(lambda field: field[1].m_Level == 1, enumerate(fields))
363-
):
364-
if dep < pa_dep1:
365-
# Skip parent fields at lvl1
366-
continue
367-
if i + 1 < len(fields) and fields[i + 1].m_Type == "Array":
368-
field.m_Type = fields[i + 3].m_Type + "[]"
369-
name, type = field.m_Name, translate_type(
370-
field.m_Type, typenames=classname_nodes | import_defs
371-
)
372-
emit_line(f"\t{declare_field(name, type, field.m_Type)}")
373-
clazz_fields.append((name, type, field.m_Type))
374-
cur_dep1 += 1
375-
dp[clazz] = cur_dep1
376-
else:
377-
# No inheritance
378-
emit_line(f"class {clazz}:")
379-
for field in fields:
380-
name, type = field.m_Name, translate_type(
381-
field.m_Type, typenames=classname_nodes | import_defs
382-
)
383-
emit_line(f"\t{declare_field(name, type, field.m_Type)}")
384-
clazz_fields.append((name, type))
385-
dp[clazz] = len(fields)
348+
emit_line(f"class {clazz}:")
349+
for field in fields:
350+
if field.m_Type == clazz:
351+
continue
352+
if field.m_Level > 1:
353+
# Nested type. We should have already defined it
354+
# with type hints
355+
continue
356+
name, type = field.m_Name, translate_type(
357+
field.m_Type, typenames=classname_nodes | import_defs
358+
)
359+
emit_line(f"\t{declare_field(name, type, field.m_Type)}")
360+
clazz_fields.append((name, type))
361+
386362
if not clazz_fields:
387363
# Empty class. Consider MRO
388364
emit_line("\tpass")
@@ -464,7 +440,7 @@ def __main__():
464440
parser.add_argument(
465441
"--backend",
466442
help="Backend to use for code generation",
467-
default="AssetRipper",
443+
default="AssetStudio",
468444
)
469445
parser.add_argument(
470446
"--filter",
@@ -476,8 +452,8 @@ def __main__():
476452
help="[JSON] Load tree dump in json format {str[fullname]: List[TypeTreeNode]},...",
477453
)
478454
parser.add_argument(
479-
"--asm",
480-
help="[Asm] Load typetree dump from game assembly DLL",
455+
"--asm-dir",
456+
help="[Asm] Load typetree dump from game assembly DLL folder",
481457
type=str
482458
)
483459
parser.add_argument(
@@ -508,12 +484,23 @@ def __main__():
508484
gen = TypeTreeGenerator(args.unity_version, args.backend)
509485
def populate_gen():
510486
# https://github.com/UnityPy-Org/TypeTreeGeneratorAPI/pull/1
511-
for asm,clz in gen.get_monobehavior_definitions():
512-
node = gen.get_nodes_as_json(asm, clz)
513-
pass
514-
if args.asm:
515-
print("Loading .NET Assembly", args.asm)
516-
gen.load_dll(args.asm)
487+
for asm,clz in gen.get_class_definitions():
488+
try:
489+
node = gen.get_nodes_as_json(asm, clz)
490+
node = json.loads(node)
491+
typetree[clz] = node
492+
except Exception as e:
493+
logger.warning(f"Skipping nodes for {asm}.{clz}: {e}")
494+
if args.asm_dir:
495+
print("Loading .NET Assemblies", args.asm_dir)
496+
for dll in os.listdir(args.asm_dir):
497+
if not dll.lower().endswith(".dll"):
498+
continue
499+
try:
500+
print(f"Loading {dll}")
501+
gen.load_dll(open(os.path.join(args.asm_dir, dll), "rb").read())
502+
except Exception as e:
503+
logger.warning(f"Skipping {dll}: {e}")
517504
populate_gen()
518505
elif args.il2cpp and args.metadata:
519506
print("Loading IL2CPP", args.il2cpp, args.metadata)
@@ -526,6 +513,8 @@ def populate_gen():
526513
else:
527514
raise ValueError("No valid input source specified.")
528515
if typetree:
516+
with open(".typetree.json", "w") as f:
517+
json.dump(typetree, f, indent=4)
529518
regex = re.compile(args.filter)
530519
typetree = {k: v for k, v in typetree.items() if regex.match(k)}
531520
process_typetree(typetree, args.outdir)

0 commit comments

Comments
 (0)