Skip to content

Commit 3dda24b

Browse files
feat: read preload table to get path id (#372)
* feat: read preload table to get path id * refactor: only build container index once * fix: encapsulate lock * fix: condition
1 parent 59af5e2 commit 3dda24b

3 files changed

Lines changed: 41 additions & 1 deletion

File tree

UnityPy/environment.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@ class Environment:
3232
local_files: List[str]
3333
local_files_simple: List[str]
3434
typetree_generator: Optional["TypeTreeGenerator"] = None
35+
_container_index_built: bool = False
3536

3637
def __init__(self, *args: FileSourceType, fs: Optional[AbstractFileSystem] = None, path: Optional[str] = None):
3738
self.files = {}
3839
self.cabs = {}
3940
self.fs = fs or LocalFileSystem()
4041
self.local_files = []
4142
self.local_files_simple = []
43+
self._container_index_built = False
4244

4345
if path is None:
4446
# if no path is given, use the current working directory
@@ -203,9 +205,19 @@ def search(item):
203205

204206
return search(self)
205207

208+
def _build_container_index(self) -> None:
209+
if self._container_index_built:
210+
return
211+
212+
self._container_index_built = True
213+
for f in self.cabs.values():
214+
if isinstance(f, SerializedFile):
215+
f.container.parse_preload_table()
216+
206217
@property
207218
def container(self) -> ContainerHelper:
208219
"""Returns a dictionary of all objects in the Environment."""
220+
self._build_container_index()
209221
container = []
210222
for f in self.cabs.values():
211223
if isinstance(f, SerializedFile) and not f.is_dependency:
@@ -249,6 +261,7 @@ def register_cab(self, name: str, item: Union[SerializedFile, EndianBinaryReader
249261
The file to register.
250262
"""
251263
self.cabs[simplify_name(name)] = item
264+
self._container_index_built = False
252265

253266
def get_cab(self, name: str) -> Union[SerializedFile, EndianBinaryReader, None]:
254267
"""

UnityPy/files/ObjectReader.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ def peek_name(self) -> Union[str, None]:
198198

199199
@property
200200
def container(self):
201+
env = self.assets_file.environment
202+
if env is not None:
203+
env._build_container_index()
201204
return self.assets_file._container.path_dict.get(self.path_id)
202205

203206
@property

UnityPy/helpers/ContainerHelper.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from __future__ import annotations
22

3-
from typing import TYPE_CHECKING, Dict, Generator, Iterator, List, Tuple, Union
3+
from typing import TYPE_CHECKING, Dict, Generator, Iterator, List, Optional, Tuple, Union
44

55
from attrs import define
66

@@ -16,13 +16,37 @@ class ContainerHelper:
1616
container: List[Tuple[str, AssetInfo]]
1717
container_dict: Dict[str, PPtr[Object]]
1818
path_dict: Dict[int, str]
19+
_preload_table: Optional[List[PPtr[Object]]] = None
1920

2021
def __init__(self, container: Union[List[Tuple[str, AssetInfo]], AssetBundle]) -> None:
22+
preload_table: Optional[List[PPtr[Object]]] = None
2123
if not isinstance(container, (list)):
24+
preload_table = container.m_PreloadTable
2225
container = container.m_Container
2326
self.container = container
2427
self.container_dict = {key: value.asset for key, value in container}
2528
self.path_dict = {value.asset.path_id: key for key, value in container}
29+
self._preload_table = preload_table
30+
31+
def parse_preload_table(self) -> None:
32+
if self._preload_table is None:
33+
return
34+
35+
for path, info in self.container:
36+
start = info.preloadIndex
37+
size = info.preloadSize
38+
if start < 0 or size <= 0 or start + size > len(self._preload_table):
39+
continue
40+
for pptr in self._preload_table[start : start + size]:
41+
if not pptr:
42+
continue
43+
try:
44+
target = pptr.deref()
45+
except (FileNotFoundError, KeyError):
46+
continue
47+
target.assets_file._container.path_dict.setdefault(pptr.path_id, path)
48+
49+
self._preload_table = None
2650

2751
def items(self) -> Generator[Tuple[str, PPtr[Object]], None, None]:
2852
return ((key, value.asset) for key, value in self.container)

0 commit comments

Comments
 (0)