11from __future__ import annotations
2+
23import re
3- from typing import Optional , Any , Union , TYPE_CHECKING
4+ from copy import copy
5+ from typing import TYPE_CHECKING , Any , Optional , Union
46
5- from .TypeTreeNode import TypeTreeNode
6- from ..streams .EndianBinaryReader import EndianBinaryReader
7- from ..streams .EndianBinaryWriter import EndianBinaryWriter
7+ from attrs import define
88
99from .. import classes
10+ from ..streams .EndianBinaryReader import EndianBinaryReader
11+ from ..streams .EndianBinaryWriter import EndianBinaryWriter
12+ from .TypeTreeNode import TypeTreeNode
1013
1114Object = classes .Object
1215PPtr = classes .PPtr
7073}
7174
7275
76+ @define (slots = True )
77+ class TypeTreeConfig :
78+ as_dict : bool
79+ assetsfile : "Optional[SerializedFile]" = None
80+ has_registry : bool = False
81+
82+
83+ def get_ref_type_node (ref_object : dict , assetfile : SerializedFile ) -> TypeTreeNode :
84+ typ = ref_object ["type" ]
85+ if isinstance (typ , dict ):
86+ cls = typ ["class" ]
87+ ns = typ ["ns" ]
88+ asm = typ ["asm" ]
89+ else :
90+ cls = getattr (typ , "class" )
91+ ns = typ .ns
92+ asm = typ .asm
93+
94+ if not assetfile or not assetfile .ref_types :
95+ raise ValueError ("SerializedFile has no ref_types" )
96+
97+ for ref_type in assetfile .ref_types :
98+ if (
99+ cls == ref_type .m_ClassName
100+ and ns == ref_type .m_NameSpace
101+ and asm == ref_type .m_AssemblyName
102+ ):
103+ return ref_type .node
104+ else :
105+ raise ValueError (f"Referenced type not found: { cls } { ns } { asm } " )
106+
107+
73108def read_typetree (
74109 root_node : TypeTreeNode ,
75110 reader : EndianBinaryReader ,
@@ -98,7 +133,8 @@ def read_typetree(
98133 )
99134
100135 pos = reader .Position
101- obj = read_value (root_node , reader , as_dict , assetsfile )
136+ config = TypeTreeConfig (as_dict , assetsfile , False )
137+ obj = read_value (root_node , reader , config )
102138
103139 read = reader .Position - pos
104140 if expected_read is not None and read != expected_read :
@@ -131,8 +167,7 @@ def write_typetree(
131167def read_value (
132168 node : TypeTreeNode ,
133169 reader : EndianBinaryReader ,
134- as_dict : bool ,
135- assetsfile : Optional [SerializedFile ],
170+ config : TypeTreeConfig ,
136171) -> Any :
137172 # print(reader.Position, node.m_Name, node.m_Type, node.m_MetaFlag)
138173 align = metaflag_is_aligned (node .m_MetaFlag )
@@ -141,9 +176,17 @@ def read_value(
141176 if func :
142177 value = func (reader )
143178 elif node .m_Type == "pair" :
144- first = read_value (node .m_Children [0 ], reader , as_dict , assetsfile )
145- second = read_value (node .m_Children [1 ], reader , as_dict , assetsfile )
179+ first = read_value (node .m_Children [0 ], reader , config )
180+ second = read_value (node .m_Children [1 ], reader , config )
146181 value = (first , second )
182+ elif node .m_Type == "ReferencedObject" :
183+ value = {}
184+ for child in node .m_Children :
185+ if child .m_Type == "ReferencedObjectData" :
186+ ref_type_nodes = get_ref_type_node (value , config .assetsfile )
187+ value [child .m_Name ] = read_value (ref_type_nodes , reader , config )
188+ else :
189+ value [child .m_Name ] = read_value (child , reader , config )
147190 # Vector
148191 elif node .m_Children and node .m_Children [0 ].m_Type == "Array" :
149192 if metaflag_is_aligned (node .m_Children [0 ].m_MetaFlag ):
@@ -153,22 +196,25 @@ def read_value(
153196 size = reader .read_int ()
154197 subtype = node .m_Children [0 ].m_Children [1 ]
155198 if metaflag_is_aligned (subtype .m_MetaFlag ):
156- value = read_value_array (subtype , reader , as_dict , size , assetsfile )
199+ value = read_value_array (subtype , reader , config )
157200 else :
158- value = [
159- read_value (subtype , reader , as_dict , assetsfile ) for _ in range (size )
160- ]
201+ value = [read_value (subtype , reader , config ) for _ in range (size )]
161202
162203 else : # Class
163- value = {
164- child .m_Name : read_value (child , reader , as_dict , assetsfile )
165- for child in node .m_Children
166- }
204+ value = {}
205+ for child in node .m_Children :
206+ if child .m_Type == "ManagedReferencesRegistry" :
207+ if config .has_registry :
208+ continue
209+ else :
210+ config = copy (config )
211+ config .has_registry = True
212+ value [child .m_Name ] = read_value (child , reader , config )
167213
168- if not as_dict :
214+ if not config . as_dict :
169215 if node .m_Type .startswith ("PPtr<" ):
170216 value = PPtr [Any ](
171- assetsfile = assetsfile ,
217+ assetsfile = config . assetsfile ,
172218 m_FileID = value ["m_FileID" ],
173219 m_PathID = value ["m_PathID" ],
174220 )
@@ -198,9 +244,8 @@ def read_value(
198244def read_value_array (
199245 node : TypeTreeNode ,
200246 reader : EndianBinaryReader ,
201- as_dict : bool ,
247+ config : TypeTreeConfig ,
202248 size : int ,
203- assetsfile : Optional [SerializedFile ],
204249) -> Any :
205250 align = metaflag_is_aligned (node .m_MetaFlag )
206251
@@ -217,38 +262,44 @@ def read_value_array(
217262
218263 key_func = FUNCTION_READ_MAP .get (
219264 key_node .m_Type ,
220- lambda reader : read_value (key_node , reader , as_dict , assetsfile ),
265+ lambda reader : read_value (key_node , reader , config ),
221266 )
222267 value_func = FUNCTION_READ_MAP .get (
223268 value_node .m_Type ,
224- lambda reader : read_value (value_node , reader , as_dict , assetsfile ),
269+ lambda reader : read_value (value_node , reader , config ),
225270 )
226271 value = [(key_func (reader ), value_func (reader )) for _ in range (size )]
272+ elif node .m_Type == "ReferencedObject" :
273+ value = [None ] * size
274+ for i in range (size ):
275+ item = {}
276+ for child in node .m_Children :
277+ if child .m_Type == "ReferencedObjectData" :
278+ ref_type_nodes = get_ref_type_node (item , config .assetsfile )
279+ item [child .m_Name ] = read_value (ref_type_nodes , reader , config )
280+ else :
281+ item [child .m_Name ] = read_value (child , reader , config )
282+ value [i ] = item
227283 # Vector
228284 elif node .m_Children and node .m_Children [0 ].m_Type == "Array" :
229285 if metaflag_is_aligned (node .m_Children [0 ].m_MetaFlag ):
230286 align = True
231287 subtype = node .m_Children [0 ].m_Children [1 ]
232288 if metaflag_is_aligned (subtype .m_MetaFlag ):
233289 value = [
234- read_value_array (
235- subtype , reader , as_dict , reader .read_int (), assetsfile
236- )
290+ read_value_array (subtype , reader , config , reader .read_int ())
237291 for _ in range (size )
238292 ]
239293 else :
240294 value = [
241- [
242- read_value (subtype , reader , as_dict , assetsfile )
243- for _ in range (reader .read_int ())
244- ]
295+ [read_value (subtype , reader , config ) for _ in range (reader .read_int ())]
245296 for _ in range (size )
246297 ]
247298 else : # Class
248- if as_dict :
299+ if config . as_dict :
249300 value = [
250301 {
251- child .m_Name : read_value (child , reader , as_dict , assetsfile )
302+ child .m_Name : read_value (child , reader , config )
252303 for child in node .m_Children
253304 }
254305 for _ in range (size )
@@ -257,9 +308,9 @@ def read_value_array(
257308 if node .m_Type .startswith ("PPtr<" ):
258309 value = [
259310 PPtr [Any ](
260- assetsfile = assetsfile ,
311+ assetsfile = config . assetsfile ,
261312 ** {
262- child .m_Name : read_value (child , reader , as_dict , assetsfile )
313+ child .m_Name : read_value (child , reader , config )
263314 for child in node .m_Children
264315 },
265316 )
@@ -276,7 +327,7 @@ def read_value_array(
276327 value = [
277328 clz (
278329 ** {
279- name : read_value (child , reader , as_dict , assetsfile )
330+ name : read_value (child , reader , config )
280331 for name , child in zip (clean_names , node .m_Children )
281332 }
282333 )
@@ -287,9 +338,7 @@ def read_value_array(
287338 value = [None ] * size
288339 for i in range (size ):
289340 value_i_d = {
290- clean_name (child .m_Name ): read_value (
291- child , reader , as_dict , assetsfile
292- )
341+ clean_name (child .m_Name ): read_value (child , reader , config )
293342 for child in node .m_Children
294343 }
295344 value_i = clz (
0 commit comments