1- from io import BytesIO
2- import os
31import json
2+ import os
3+ from io import BytesIO
4+ from pathlib import Path
5+ from typing import Callable , Dict , List , Union
6+
47import UnityPy
58from UnityPy .classes import (
9+ AudioClip ,
10+ Font ,
11+ GameObject ,
12+ Mesh ,
13+ MonoBehaviour ,
614 Object ,
715 PPtr ,
8- MonoBehaviour ,
9- TextAsset ,
10- Font ,
1116 Shader ,
12- Mesh ,
1317 Sprite ,
18+ TextAsset ,
1419 Texture2D ,
15- AudioClip ,
16- GameObject ,
1720)
1821from UnityPy .enums .ClassIDType import ClassIDType
19- from typing import Union , List , Dict , Callable
20- from pathlib import Path
2122
2223
2324def export_obj (
@@ -57,7 +58,7 @@ def export_obj(
5758 return []
5859
5960 if append_name :
60- fp = os .path .join (fp , obj .name if obj . name else obj .type .name )
61+ fp = os .path .join (fp , obj .m_Name if getattr ( obj , "m_Name" ) else obj .type .name )
6162
6263 fp , extension = os .path .splitext (fp )
6364
@@ -114,7 +115,7 @@ def defaulted_export_index(type: ClassIDType):
114115 # the check of the various sub directories is required to avoid // in the path
115116 obj_dest = os .path .join (
116117 dst ,
117- * (x for x in obj_path .split ("/" )[: ignore_first_container_dirs ] if x ),
118+ * (x for x in obj_path .split ("/" )[ignore_first_container_dirs : ] if x ),
118119 )
119120 os .makedirs (os .path .dirname (obj_dest ), exist_ok = True )
120121 exported .extend (
@@ -156,8 +157,8 @@ def exportTextAsset(obj: TextAsset, fp: str, extension: str = ".txt") -> List[in
156157 if not extension :
157158 extension = ".txt"
158159 with open (f"{ fp } { extension } " , "wb" ) as f :
159- f .write (obj .script )
160- return [(obj .assets_file , obj .path_id )]
160+ f .write (obj .m_Script . encode ( "utf-8" , "surrogateescape" ) )
161+ return [(obj .assets_file , obj .object_reader . path_id )]
161162
162163
163164def exportFont (obj : Font , fp : str , extension : str = "" ) -> List [int ]:
@@ -167,65 +168,60 @@ def exportFont(obj: Font, fp: str, extension: str = "") -> List[int]:
167168 if obj .m_FontData [0 :4 ] == b"OTTO" :
168169 extension = ".otf"
169170 with open (f"{ fp } { extension } " , "wb" ) as f :
170- f .write (obj .m_FontData )
171- return [(obj .assets_file , obj .path_id )]
171+ f .write (bytes ( obj .m_FontData ) )
172+ return [(obj .assets_file , obj .object_reader . path_id )]
172173
173174
174175def exportMesh (obj : Mesh , fp : str , extension = ".obj" ) -> List [int ]:
175176 if not extension :
176177 extension = ".obj"
177178 with open (f"{ fp } { extension } " , "wt" , encoding = "utf8" , newline = "" ) as f :
178179 f .write (obj .export ())
179- return [(obj .assets_file , obj .path_id )]
180+ return [(obj .assets_file , obj .object_reader . path_id )]
180181
181182
182183def exportShader (obj : Shader , fp : str , extension = ".txt" ) -> List [int ]:
183184 if not extension :
184185 extension = ".txt"
185186 with open (f"{ fp } { extension } " , "wt" , encoding = "utf8" , newline = "" ) as f :
186187 f .write (obj .export ())
187- return [(obj .assets_file , obj .path_id )]
188+ return [(obj .assets_file , obj .object_reader . path_id )]
188189
189190
190191def exportMonoBehaviour (
191192 obj : Union [MonoBehaviour , Object ], fp : str , extension : str = ""
192193) -> List [int ]:
193194 export = None
194- # TODO - add generic way to add external typetrees
195- if obj .serialized_type and obj .serialized_type .node :
196- extension = ".json"
197- export = json .dumps (obj .read_typetree (), indent = 4 , ensure_ascii = False ).encode (
198- "utf8" , errors = "surrogateescape"
199- )
195+
196+ if obj .object_reader .serialized_type .node :
197+ # a typetree is available from the SerializedFile for this object
198+ export = obj .object_reader .read_typetree ()
200199 elif isinstance (obj , MonoBehaviour ):
201- # no set typetree
202- # check if we have a script
203- script = obj .m_Script
204- if script :
200+ # try to get the typetree from the MonoBehavior script
201+ script_ptr = obj .m_Script
202+ if script_ptr :
205203 # looks like we have a script
206- script = script .read ()
204+ script = script_ptr .read ()
207205 # check if there is a locally stored typetree for it
208206 nodes = MONOBEHAVIOUR_TYPETREES .get (script .m_AssemblyName , {}).get (
209207 script .m_ClassName , None
210208 )
211209 if nodes :
212- # we have a typetree
213- # adjust the name
214- # name = (
215- # f"{script.m_ClassName}-{obj.name}"
216- # if obj.name
217- # else script.m_ClassName
218- # )
219- extension = ".json"
220- export = json .dumps (
221- obj .read_typetree (nodes ), indent = 4 , ensure_ascii = False
222- ).encode ("utf8" , errors = "surrogateescape" )
210+ export = obj .object_reader .read_typetree (nodes )
211+ else :
212+ export = obj .object_reader .read_typetree ()
213+
223214 if not export :
224215 extension = ".bin"
225- export = obj .raw_data
216+ export = obj .object_reader .raw_data
217+ else :
218+ extension = ".json"
219+ export = json .dumps (export , indent = 4 , ensure_ascii = False ).encode (
220+ "utf8" , errors = "surrogateescape"
221+ )
226222 with open (f"{ fp } { extension } " , "wb" ) as f :
227223 f .write (export )
228- return [(obj .assets_file , obj .path_id )]
224+ return [(obj .assets_file , obj .object_reader . path_id )]
229225
230226
231227def exportAudioClip (obj : AudioClip , fp : str , extension : str = "" ) -> List [int ]:
@@ -240,16 +236,16 @@ def exportAudioClip(obj: AudioClip, fp: str, extension: str = "") -> List[int]:
240236 for name , clip_data in samples .items ():
241237 with open (os .path .join (fp , f"{ name } .wav" ), "wb" ) as f :
242238 f .write (clip_data )
243- return [(obj .assets_file , obj .path_id )]
239+ return [(obj .assets_file , obj .object_reader . path_id )]
244240
245241
246242def exportSprite (obj : Sprite , fp : str , extension : str = ".png" ) -> List [int ]:
247243 if not extension :
248244 extension = ".png"
249245 obj .image .save (f"{ fp } { extension } " )
250246 exported = [
251- (obj .assets_file , obj .path_id ),
252- (obj .m_RD .texture .assets_file , obj .m_RD .texture .path_id ),
247+ (obj .assets_file , obj .object_reader . path_id ),
248+ (obj .m_RD .texture .assetsfile , obj .m_RD .texture .path_id ),
253249 ]
254250 alpha_assets_file = getattr (obj .m_RD .alphaTexture , "assets_file" , None )
255251 alpha_path_id = getattr (obj .m_RD .alphaTexture , "path_id" , None )
@@ -322,8 +318,7 @@ def crawl_obj(obj: Object, ret: dict = None) -> Dict[int, Union[Object, PPtr]]:
322318 # MonoBehaviour really on their typetree
323319 # while Object denotes that the class of the object isn't implemented yet
324320 if isinstance (obj , (MonoBehaviour , Object )):
325- obj .read_typetree ()
326- data = obj .type_tree .__dict__ .values ()
321+ data = obj .read_typetree ().__dict__ .values ()
327322 else :
328323 data = obj .__dict__ .values ()
329324
0 commit comments