-
Notifications
You must be signed in to change notification settings - Fork 64
/
palsav.py
71 lines (63 loc) · 2.74 KB
/
palsav.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import zlib
MAGIC_BYTES = b"PlZ"
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]
data_start_offset = 12
# Check for magic bytes
if magic_bytes == b"CNK":
uncompressed_len = int.from_bytes(data[12:16], byteorder="little")
compressed_len = int.from_bytes(data[16:20], byteorder="little")
magic_bytes = data[20:23]
save_type = data[23]
data_start_offset = 24
if magic_bytes != MAGIC_BYTES:
if (
magic_bytes == b"\x00\x00\x00"
and uncompressed_len == 0
and compressed_len == 0
):
raise Exception(
f"not a compressed Palworld save, found too many null bytes, this is likely corrupted"
)
raise Exception(
f"not a compressed Palworld save, found {magic_bytes!r} instead of {MAGIC_BYTES!r}"
)
# 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) - data_start_offset:
raise Exception(f"incorrect compressed length: {compressed_len}")
# Decompress file
uncompressed_data = zlib.decompress(data[data_start_offset:])
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
def compress_gvas_to_sav(data: bytes, save_type: int) -> bytes:
uncompressed_len = len(data)
compressed_data = zlib.compress(data)
compressed_len = len(compressed_data)
if save_type == 0x32:
compressed_data = zlib.compress(compressed_data)
# Create a byte array and append the necessary information
result = bytearray()
result.extend(uncompressed_len.to_bytes(4, byteorder="little"))
result.extend(compressed_len.to_bytes(4, byteorder="little"))
result.extend(MAGIC_BYTES)
result.extend(bytes([save_type]))
result.extend(compressed_data)
return bytes(result)