cheahjs / palworld-save-tools

Tools for converting Palworld .sav files to JSON and back
MIT License
781 stars 67 forks source link

Issue Encountered: Error in 'decompress_sav_to_gvas' while Converting 'Level.sav' to JSON #76

Closed w569111843 closed 6 months ago

w569111843 commented 6 months ago

I encountered a situation where the disk space was filled up during server operation. The 'LevelMeta.sav' file in my save folder became 0 bytes, but the 'Level.sav' file and the data in the 'Players' folder are still present. How can I use this tool to fix my save?

Additionally, when I try to use this tool to convert 'Level.sav' to JSON, an error occurs in 'palworld-save-tools-main\lib\palsav.py', specifically in the 'decompress_sav_to_gvas' function at line 25:

uncompressed_data = zlib.decompress(data[12:])

The error message is:

zlib.error: Error -5 while decompressing data: incomplete or truncated stream

How can I resolve this issue?"

w569111843 commented 6 months ago

The following is the complete error message

python convert.py .\Level.sav --to-json Converting .\Level.sav to JSON, saving to .\Level.sav.json Decompressing sav file Traceback (most recent call last): File "C:\Users\Desktop\palworld-save-tools-main\convert.py", line 115, in main() File "C:\Users\Desktop\palworld-save-tools-main\convert.py", line 53, in main convert_sav_to_json(args.filename, output_path, args.minify_json) File "C:\Users\Desktop\palworld-save-tools-main\convert.py", line 72, in convert_sav_to_json rawgvas, = decompress_sav_to_gvas(data) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\Desktop\palworld-save-tools-main\lib\palsav.py", line 25, in decompress_sav_to_gvas uncompressed_data = zlib.decompress(data[12:]) ^^^^^^^^^^^^^^^^^^^^^^^^^^ zlib.error: Error -5 while decompressing data: incomplete or truncated stream

w569111843 commented 6 months ago

I found the solution to this error. It involves replacing zlib.decompress in palsav.py with a streaming decompression. Here is the code:

def decompress_sav_to_gvas(data: bytes) -> tuple[bytes, int]:
    uncompressed_len = int.from_bytes(data[0:4], byteorder="little")
    compressed_len = int.from_bytes(data[4:8], byteorder="little")
    magic_bytes = data[8:11]
    save_type = data[11]

    # Check for magic bytes
    if magic_bytes != b"PlZ":
        raise Exception(
            f"not a compressed Palworld save, found {magic_bytes} instead of P1Z"
        )

    # Valid save types
    if save_type not in [0x30, 0x31, 0x32]:
        raise Exception(f"unknown save type: {save_type}")

    # We only have 0x31 (single zlib) and 0x32 (double zlib) saves
    if save_type not in [0x31, 0x32]:
        raise Exception(f"unhandled compression type: {save_type}")

    if save_type == 0x31:
        # Check if the compressed length is correct
        if compressed_len != len(data) - 12:
            raise Exception(f"incorrect compressed length: {compressed_len}")

    # Decompress file using streaming decompression
    decompressor = zlib.decompressobj()
    uncompressed_data = decompressor.decompress(data[12:] + decompressor.flush())

    if save_type == 0x32:
        # Check if the compressed length is correct
        if compressed_len != len(uncompressed_data):
            raise Exception(f"incorrect compressed length: {compressed_len}")

        # Decompress file
        uncompressed_data = zlib.decompress(uncompressed_data)

    # Check if the uncompressed length is correct
    if uncompressed_len != len(uncompressed_data):
        raise Exception(f"incorrect uncompressed length: {uncompressed_len}")

    return uncompressed_data, save_type

This modification replaces the direct use of zlib.decompress with a streaming approach using decompressobj. This change addresses the reported error.

w569111843 commented 6 months ago

But there is another issue: the lengths of uncompressed_data and compressed_len for the problematic save file are no longer the same (uncompressed_data < compressed_len). Is it possible to fix this situation?

w569111843 commented 6 months ago

[Uploading Level.zip…]() This is an sav file that cannot be read correctly. I really need your help.

w569111843 commented 6 months ago

Level.zip I'm sorry, the upload was not successful just now

cheahjs commented 6 months ago

This is a sign of data corruption, in this case the save file being truncated before it was fully written to disk. Switching to a streaming decompressor just masks the issue, hence the check for uncompressed_len fails.

w569111843 commented 6 months ago

This is a sign of data corruption. In this case, the save file was truncated before it was fully written to disk. Even when testing with an intact archive, an error -5 occurs during data decompression, indicating an incomplete or truncated stream. However, switching to a streaming decompressor allows successful decryption.