44from importlib .resources import open_binary
55from io import BytesIO
66from struct import Struct
7- from typing import Any , Dict , List , Optional , Tuple
7+ from typing import Any , Dict , List , Optional , Tuple , TypeVar
88
99from .TypeTreeHelper import TypeTreeNode
10+ from .UnityVersion import UnityVersion
1011
11- TPKTYPETREE : TpkTypeTreeBlob = None
12- CLASSES_CACHE : Dict [Tuple [int , tuple ], TypeTreeNode ] = {}
12+ T = TypeVar ("T" )
13+
14+ TPKTYPETREE : TpkTypeTreeBlob = None # pyright: ignore[reportAssignmentType]
15+ CLASSES_CACHE : Dict [Tuple [int , UnityVersion ], TypeTreeNode ] = {}
1316NODES_CACHE : Dict [TpkUnityClass , TypeTreeNode ] = {}
1417
1518
@@ -24,14 +27,14 @@ def init():
2427 TPKTYPETREE = blob
2528
2629
27- def get_typetree_node (class_id : int , version : tuple ):
30+ def get_typetree_node (class_id : int , version : UnityVersion ):
2831 global CLASSES_CACHE
2932 key = (class_id , version )
3033 cached = CLASSES_CACHE .get (key )
3134 if cached :
3235 return cached
3336
34- class_info = TPKTYPETREE .ClassInformation [class_id ].getVersionedClass (UnityVersion . fromList ( * version ) )
37+ class_info = TPKTYPETREE .ClassInformation [class_id ].getVersionedClass (version )
3538 if class_info is None :
3639 raise ValueError ("Could not find class info for class id {}" .format (class_id ))
3740
@@ -87,15 +90,6 @@ class TpkCompressionType(IntEnum):
8790 Brotli = 3
8891
8992
90- class UnityVersionType (IntEnum ):
91- Alpha = 0
92- Beta = 1
93- China = 2
94- Final = 3
95- Patch = 4
96- Experimental = 5
97-
98-
9993class TpkDataType (IntEnum ):
10094 TypeTreeInformation = 0
10195 Collection = 1
@@ -168,7 +162,7 @@ def __init__(self, stream: BytesIO):
168162 raise Exception ("Invalid compressed size" )
169163
170164 def GetDataBlob (self ) -> TpkDataBlob :
171- decompressed = None
165+ decompressed : bytes
172166 if self .CompressionType == TpkCompressionType .NONE :
173167 decompressed = self .CompressedBytes
174168
@@ -185,7 +179,7 @@ def GetDataBlob(self) -> TpkDataBlob:
185179 elif self .CompressionType == TpkCompressionType .Brotli :
186180 import brotli
187181
188- decompressed : bytes = brotli .decompress (self .CompressedBytes )
182+ decompressed = brotli .decompress (self .CompressedBytes )
189183
190184 else :
191185 raise Exception ("Invalid compression type" )
@@ -228,7 +222,7 @@ class TpkTypeTreeBlob(TpkDataBlob):
228222 def __init__ (self , stream : BytesIO ) -> None :
229223 (self .CreationTime ,) = INT64 .unpack (stream .read (INT64 .size ))
230224 (versionCount ,) = INT32 .unpack (stream .read (INT32 .size ))
231- self .Versions = [UnityVersion . fromStream (stream ) for _ in range (versionCount )]
225+ self .Versions = [read_version (stream ) for _ in range (versionCount )]
232226 (classCount ,) = INT32 .unpack (stream .read (INT32 .size ))
233227 self .ClassInformation = {x .ID : x for x in (TpkClassInformation (stream ) for _ in range (classCount ))}
234228 self .CommonString = TpkCommonString (stream )
@@ -282,52 +276,6 @@ def __init__(self, stream: BytesIO) -> None:
282276######################################################################################
283277
284278
285- class UnityVersion (int ):
286- # https://github.com/AssetRipper/VersionUtilities/blob/master/VersionUtilities/UnityVersion.cs
287- """
288- use following static methods instead of the constructor(__init__):
289- UnityVersion.fromStream(stream: BytesIO)
290- UnityVersion.fromString(version: str)
291- UnityVersion.fromList(major: int, minor: int, patch: int, build: int)
292- """
293-
294- @staticmethod
295- def fromStream (stream : BytesIO ) -> UnityVersion :
296- (m_data ,) = UINT64 .unpack (stream .read (UINT64 .size ))
297- return UnityVersion (m_data )
298-
299- @staticmethod
300- def fromString (version : str ) -> UnityVersion :
301- return UnityVersion .fromList (* map (int , version .split ("." )))
302-
303- @staticmethod
304- def fromList (major : int = 0 , minor : int = 0 , patch : int = 0 , build : int = 0 ) -> UnityVersion :
305- return UnityVersion (major << 48 | minor << 32 | patch << 16 | build )
306-
307- @property
308- def major (self ) -> int :
309- return (self >> 48 ) & 0xFFFF
310-
311- @property
312- def minor (self ) -> int :
313- return (self >> 32 ) & 0xFFFF
314-
315- @property
316- def build (self ) -> int :
317- return (self >> 16 ) & 0xFFFF
318-
319- @property
320- def type (self ) -> int :
321- return UnityVersionType (self >> 8 ) & 0xFF
322-
323- @property
324- def type_number (self ) -> int :
325- return self & 0xFF
326-
327- def __repr__ (self ) -> str :
328- return f"UnityVersion { self .major } .{ self .minor } .{ self .build } .{ self .type_number } "
329-
330-
331279class TpkUnityClass :
332280 __slots__ = ("Name" , "Base" , "Flags" , "EditorRootNode" , "ReleaseRootNode" )
333281 Struct = Struct ("<HHb" )
@@ -374,20 +322,20 @@ class TpkClassInformation:
374322 __slots__ = ("ID" , "Classes" )
375323 ID : int
376324 # TODO - might want to use dict
377- Classes : List [Tuple [UnityVersion , TpkUnityClass ]]
325+ Classes : List [Tuple [UnityVersion , Optional [ TpkUnityClass ] ]]
378326
379327 def __init__ (self , stream : BytesIO ) -> None :
380328 (self .ID ,) = INT32 .unpack (stream .read (INT32 .size ))
381329 (count ,) = INT32 .unpack (stream .read (INT32 .size ))
382330 self .Classes = [
383331 (
384- UnityVersion . fromStream (stream ),
332+ read_version (stream ),
385333 TpkUnityClass (stream ) if stream .read (1 )[0 ] else None ,
386334 )
387335 for _ in range (count )
388336 ]
389337
390- def getVersionedClass (self , version : UnityVersion ) -> TpkUnityClass :
338+ def getVersionedClass (self , version : UnityVersion ) -> Optional [ TpkUnityClass ] :
391339 return get_item_for_version (version , self .Classes )
392340
393341
@@ -469,7 +417,7 @@ class TpkCommonString:
469417
470418 def __init__ (self , stream : BytesIO ) -> None :
471419 (versionCount ,) = INT32 .unpack (stream .read (INT32 .size ))
472- self .VersionInformation = [(UnityVersion . fromStream (stream ), stream .read (1 )[0 ]) for _ in range (versionCount )]
420+ self .VersionInformation = [(read_version (stream ), stream .read (1 )[0 ]) for _ in range (versionCount )]
473421 (indicesCount ,) = INT32 .unpack (stream .read (INT32 .size ))
474422 indicesStruct = Struct (f"<{ indicesCount } H" )
475423 self .StringBufferIndices = indicesStruct .unpack (stream .read (indicesStruct .size ))
@@ -512,7 +460,11 @@ def read_data(stream: BytesIO) -> bytes:
512460 return stream .read (INT32 .unpack (stream .read (INT32 .size ))[0 ])
513461
514462
515- def get_item_for_version (exactVersion : UnityVersion , items : List [Tuple [UnityVersion , Any ]]) -> Any :
463+ def read_version (stream : BytesIO ) -> UnityVersion :
464+ return UnityVersion (UINT64 .unpack (stream .read (UINT64 .size ))[0 ])
465+
466+
467+ def get_item_for_version (exactVersion : UnityVersion , items : List [Tuple [UnityVersion , T ]]) -> T :
516468 ret = None
517469 for version , item in items :
518470 if exactVersion >= version :
0 commit comments