-
-
Notifications
You must be signed in to change notification settings - Fork 160
Description
Code
In this example, we have
>>> sf.externals
[<FileIdentifier(globalgamemanagers.assets)>, <FileIdentifier(Resources/unity_builtin_extra)>, <FileIdentifier(Library/unity default resources)>]however, the directory Library does not exist, and unity default resources is located in Resources. i.e., there is some error in the game assets.
import UnityPy
am = UnityPy.AssetsManager()
am.load_file("/path/to/sharedassets0.assets")
sf, = am.assets
clips = [v for v in sf.objects.values() if v.type == 82]
clip = clips[0].read()
clip.samplesAlternately:
conv = UnityPy.export.AudioClipConverter
conv.extract_audioclip_samples(clip)
Error
>>> conv.extract_audioclip_samples(obj)
Traceback (most recent call last):
File "<python-input-33>", line 1, in <module>
conv.extract_audioclip_samples(obj)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
File "/path/to/python3.13/site-packages/UnityPy/export/AudioClipConverter.py", line 97, in extract_audioclip_samples
audio_data = get_resource_data(
resource.m_Source,
...<2 lines>...
resource.m_Size,
)
File "/path/to/python3.13/site-packages/UnityPy/helpers/ResourceReader.py", line 28, in get_resource_data
assets_file.load_dependencies(possible_names)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
File "/path/to/python3.13/site-packages/UnityPy/files/SerializedFile.py", line 364, in load_dependencies
self.environment.load_file(file_id.path, True)
~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
File "/path/to/python3.13/site-packages/UnityPy/environment.py", line 125, in load_file
file = os.path.join(self.path, file)
File "<frozen posixpath>", line 77, in join
TypeError: expected str, bytes or os.PathLike object, not NoneTypeBug
The key code region that triggers the error is in SerializedFile:
def load_dependencies(self, possible_dependencies: list = []):
...
for file_id in self.externals:
self.environment.load_file(file_id.path, True)
for dependency in possible_dependencies:
try:
self.environment.load_file(dependency, True)
except FileNotFoundError:
passSpecifically, there are two issues. The first issue is that there is no error handling when a file_id.path in self.externals does not exist, as there is in the case that a dependency does not exist just below. If this were the only issue, I would just make a PR as it's a simple fix for an edge case of errant game asset data. However, there is another issue that I'm not sure how to fix in a way that aligns with your design intentions for this module, as, even if the error is handled, in both the case of non-existent dependencies and non-existent externals, the UnityPy still crashes, because Environment.loadfile() raises a TypeError, and not a FileNotFoundError when the file does not exist.
The reason is simple. On line 125 of Environment.py:
file = os.path.join(self.path, file)self.path may be None, as we see in the __init__ method above:
def __init__(self, *args: FileSourceType, fs: Optional[AbstractFileSystem] = None):
self.files = {}
self.cabs = {}
self.path = None
self.fs = fs or LocalFileSystem()
self.local_files = []
self.local_files_simple = []
if args:
for arg in args:
if isinstance(arg, str):
if self.fs.isfile(arg):
if ntpath.splitext(arg)[-1] in [".apk", ".zip"]:
self.load_zip_file(arg)
else:
self.path = ntpath.dirname(arg)
if reSplit.match(arg):
self.load_files([arg])
else:
self.load_file(arg)
elif self.fs.isdir(arg):
self.path = arg
self.load_folder(arg)
else:
self.path = None
self.load_file(file=arg)
if len(self.files) == 1:
self.file = list(self.files.values())[0]
if self.path == "":
self.path = os.getcwd()letting sf.environment.path = os.cwd() in the above example seems to resolve the error for me, but I'm not sure if it's causing other issues later on. Either way, it seems as though either Environment.load_file should handle the case where self.path is None or environments should always be initialized such that self.path is a string. In particular, the case
if self.path == "":
self.path = os.getcwd()seems to be intending to account for the instance where self.path is set by any keyword arguments, but it seems as though if that is the case, that self.path will be None.
For a temporary workaround, I just set sf.environment.path = os.getcwd() before trying to unpack any samples.
To Reproduce
- I used the free Peripeteia demo
- following data:
- Python 3.13
- UnityPy 1.22.5