4
4
from importlib .resources import open_binary
5
5
from io import BytesIO
6
6
from struct import Struct
7
- from typing import Any , Dict , List , Optional , Tuple
7
+ from typing import Any , Dict , List , Optional , Tuple , TypeVar
8
8
9
9
from .TypeTreeHelper import TypeTreeNode
10
+ from .UnityVersion import UnityVersion
10
11
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 ] = {}
13
16
NODES_CACHE : Dict [TpkUnityClass , TypeTreeNode ] = {}
14
17
15
18
@@ -24,14 +27,14 @@ def init():
24
27
TPKTYPETREE = blob
25
28
26
29
27
- def get_typetree_node (class_id : int , version : tuple ):
30
+ def get_typetree_node (class_id : int , version : UnityVersion ):
28
31
global CLASSES_CACHE
29
32
key = (class_id , version )
30
33
cached = CLASSES_CACHE .get (key )
31
34
if cached :
32
35
return cached
33
36
34
- class_info = TPKTYPETREE .ClassInformation [class_id ].getVersionedClass (UnityVersion . fromList ( * version ) )
37
+ class_info = TPKTYPETREE .ClassInformation [class_id ].getVersionedClass (version )
35
38
if class_info is None :
36
39
raise ValueError ("Could not find class info for class id {}" .format (class_id ))
37
40
@@ -87,15 +90,6 @@ class TpkCompressionType(IntEnum):
87
90
Brotli = 3
88
91
89
92
90
- class UnityVersionType (IntEnum ):
91
- Alpha = 0
92
- Beta = 1
93
- China = 2
94
- Final = 3
95
- Patch = 4
96
- Experimental = 5
97
-
98
-
99
93
class TpkDataType (IntEnum ):
100
94
TypeTreeInformation = 0
101
95
Collection = 1
@@ -168,7 +162,7 @@ def __init__(self, stream: BytesIO):
168
162
raise Exception ("Invalid compressed size" )
169
163
170
164
def GetDataBlob (self ) -> TpkDataBlob :
171
- decompressed = None
165
+ decompressed : bytes
172
166
if self .CompressionType == TpkCompressionType .NONE :
173
167
decompressed = self .CompressedBytes
174
168
@@ -185,7 +179,7 @@ def GetDataBlob(self) -> TpkDataBlob:
185
179
elif self .CompressionType == TpkCompressionType .Brotli :
186
180
import brotli
187
181
188
- decompressed : bytes = brotli .decompress (self .CompressedBytes )
182
+ decompressed = brotli .decompress (self .CompressedBytes )
189
183
190
184
else :
191
185
raise Exception ("Invalid compression type" )
@@ -228,7 +222,7 @@ class TpkTypeTreeBlob(TpkDataBlob):
228
222
def __init__ (self , stream : BytesIO ) -> None :
229
223
(self .CreationTime ,) = INT64 .unpack (stream .read (INT64 .size ))
230
224
(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 )]
232
226
(classCount ,) = INT32 .unpack (stream .read (INT32 .size ))
233
227
self .ClassInformation = {x .ID : x for x in (TpkClassInformation (stream ) for _ in range (classCount ))}
234
228
self .CommonString = TpkCommonString (stream )
@@ -282,52 +276,6 @@ def __init__(self, stream: BytesIO) -> None:
282
276
######################################################################################
283
277
284
278
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
-
331
279
class TpkUnityClass :
332
280
__slots__ = ("Name" , "Base" , "Flags" , "EditorRootNode" , "ReleaseRootNode" )
333
281
Struct = Struct ("<HHb" )
@@ -374,20 +322,20 @@ class TpkClassInformation:
374
322
__slots__ = ("ID" , "Classes" )
375
323
ID : int
376
324
# TODO - might want to use dict
377
- Classes : List [Tuple [UnityVersion , TpkUnityClass ]]
325
+ Classes : List [Tuple [UnityVersion , Optional [ TpkUnityClass ] ]]
378
326
379
327
def __init__ (self , stream : BytesIO ) -> None :
380
328
(self .ID ,) = INT32 .unpack (stream .read (INT32 .size ))
381
329
(count ,) = INT32 .unpack (stream .read (INT32 .size ))
382
330
self .Classes = [
383
331
(
384
- UnityVersion . fromStream (stream ),
332
+ read_version (stream ),
385
333
TpkUnityClass (stream ) if stream .read (1 )[0 ] else None ,
386
334
)
387
335
for _ in range (count )
388
336
]
389
337
390
- def getVersionedClass (self , version : UnityVersion ) -> TpkUnityClass :
338
+ def getVersionedClass (self , version : UnityVersion ) -> Optional [ TpkUnityClass ] :
391
339
return get_item_for_version (version , self .Classes )
392
340
393
341
@@ -469,7 +417,7 @@ class TpkCommonString:
469
417
470
418
def __init__ (self , stream : BytesIO ) -> None :
471
419
(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 )]
473
421
(indicesCount ,) = INT32 .unpack (stream .read (INT32 .size ))
474
422
indicesStruct = Struct (f"<{ indicesCount } H" )
475
423
self .StringBufferIndices = indicesStruct .unpack (stream .read (indicesStruct .size ))
@@ -512,7 +460,11 @@ def read_data(stream: BytesIO) -> bytes:
512
460
return stream .read (INT32 .unpack (stream .read (INT32 .size ))[0 ])
513
461
514
462
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 :
516
468
ret = None
517
469
for version , item in items :
518
470
if exactVersion >= version :
0 commit comments