ScrapHacks/tools/parse_chunked.py

118 lines
3.2 KiB
Python

from construct import *
import binascii
import os
Chunked = LazyBound(lambda: struct)
class CustomError(SymmetricAdapter):
def __init__(self, msg):
super(SymmetricAdapter, self).__init__(Pass)
self._message = msg
def _decode(self, obj, context, path):
# print("Error",path)
# print(str(context))
msg = "Invalid ID: " + repr(context.id)
raise ValidationError(message=msg, path=this.path)
RGB = NamedTuple("RGB", "R G B", Int8ul[3])
RGBA = NamedTuple("RGBA", "R G B A", Int8ul[4])
def make_chain(*sizes):
"utility function to make sequence of byte arrays"
return Sequence(*[Bytes(s) for s in sizes])
child_nodes = "children" / Struct("num" / Int32ul, "nodes" / Chunked[this.num])
subchunks = {
b"SM3\0": Struct(
"unk" / Bytes(4),
"timestamp" / Timestamp(Int32ul, 1, 1970),
child_nodes,
"scene" / Chunked,
),
b"SCN\0": Struct(
"version" / Int32ul,
"m3d_name" / PascalString(Int32ul, "utf8"),
"name" / PascalString(Int32ul, "utf8"),
child_nodes,
),
b"INI\0": Struct(
"data"
/ PrefixedArray(Int32ul, PrefixedArray(Int32ul, PascalString(Int32ul, "utf8"))),
"colors?" / Sequence(Int8ul, Int8ul, Int8ul, Int8ul, Float32l)[2],
"unk_data" / Bytes(0x18),
"unk_float" / Float32l,
"unk_int" / Int32ul,
child_nodes,
),
b"EMI\0": Struct(
"version"/Int32ul,
"num_materials"/Int32ul,
"num_unk"/Int32ul,
"materials"/Chunked
),
b"MAT\0": Struct(
"tris"/Int32ul,
"name"/PascalString(Int32ul,"utf8"),
"idx"/Bytes(this.tris*4*4)
),
None: Bytes(lambda ctx:ctx.size),
}
struct = Struct(
"id" / Bytes(4),
"size" / Int32ul,
"data" / Switch(this.id, subchunks, default=subchunks[None]),
)
def io_peek(fh, n):
p = fh.tell()
ret = fh.read(n)
fh.seek(p)
return ret
basedir = r"D:/Games/Deep Silver/Scrapland/extracted/Data.packed"
files = [
r"Models/Elements/AnilloEstructuraA/AnilloEstructuraA.SM3",
r"models/elements/antenaa/antenaa.lod1.sm3",
r"models/elements/abshield/anm/loop.cm3",
r"levels/fake/map/map3d.amc",
r"levels/shipedit/map/map3d.dum",
r"levels/menu/map/map3d.emi",
r"Models/Skies/Menu/Sky.SM3",
r"Levels/Menu/Map/Map3D.SM3",
r"Models/Elements/AnilloEstructuraD/AnilloEstructuraD.LOD1.SM3",
r"levels/menu/map/map3d.amc",
r"levels/menu/map/map3d.dum",
r"levels/menu/map/scenecamera/anm/loop.cm3",
r"models/chars/boss/boss.sm3",
r"models/chars/boss/anm/boss_walk.cm3",
]
for file in files:
file = os.path.join(basedir, file).replace("/","\\")
print()
print("#" * 3, file)
with open(file, "rb") as infile:
try:
data = struct.parse_stream(infile)
# assert infile.read()==b"","leftover data"
except Exception as ex:
print("Error:", ex)
data = None
if data:
print(data)
print("OFFSET:", hex(infile.tell()))
print("NEXT:", io_peek(infile, 16))
print("NEXT:", binascii.hexlify(io_peek(infile, 16)))