Files

42 lines
1.5 KiB
Python

"""Minimal reader of Enshrouded's KFC4 container: raw content blobs by their content key.
enshrouded.kfc header: 17 KFCLocation entries (u32 offset relative to the entry, u32 count) at 16 + i*8.
Location 1 = .dat containers, 7 = content keys (size, hash0, hash1, hash2), 8 = values
(offset u32, flags u16, container index u16, 8 bytes pad). Blobs live in enshrouded_NNN.dat.
"""
import pathlib
import struct
class KFC:
def __init__(self, game):
self.game = pathlib.Path(game)
b = (self.game / "enshrouded.kfc").read_bytes()
assert b[:4] == b"KFC4", "not a KFC4 file"
locs = []
for i in range(17):
pos = 16 + i * 8
off, cnt = struct.unpack_from("<II", b, pos)
locs.append((pos + off if off else 0, cnt))
ko, kc = locs[7]
vo, vc = locs[8]
assert kc == vc
self.content = {}
for i in range(kc):
key = struct.unpack_from("<IIII", b, ko + i * 16)
off, flags, ci = struct.unpack_from("<IHH", b, vo + i * 16)
self.content[key] = (off, flags, ci)
def read(self, size, hash0, hash1, hash2):
e = self.content.get((size, hash0, hash1, hash2))
if not e:
return None
off, _, ci = e
with open(self.game / f"enshrouded_{ci:03d}.dat", "rb") as f:
f.seek(off)
return f.read(size)
def read_hash(self, h: dict):
"""h: a descriptor's content hash {"size", "hash0", "hash1", "hash2"}."""
return self.read(h["size"], h["hash0"], h["hash1"], h["hash2"])