Skip to content

PSB Shells, Types, Platforms

Ulysses edited this page Feb 24, 2024 · 25 revisions

Shells

A PSB can be compressed/encrypted into a Shell type, and a Shell type can be decompressed/decrypted into a PSB (while PSB itself can still be encrypted).

MDF (pure)

M2 DeFlate file.

Header: mdf\0

Extensions: .mdf

Structure:

Position Content Value
0 Signature mdf\0
4 original size (uint)
8 Zlib compress header 78 9C (fast) or 78 DA (optimal)
10 Zlib compressed content

Solution:

EmtConvert pack -s MDF {file}

PsbDecompile {file}

PsBuild {file}

MFL/MZS/MXB

M2 FastLz/ZStandard/XMemCompress file.

Same as MDF, but use LZ77 (fastlz) or ZStandard or XMemCompress (MS Xbox) instead of deflate (zlib). They can also be applied with MT19937 stream encryption.

Header: mfl\0, mzs\0, mxb\0

MT19937 MDF/MFL/MZS/MXB

Must be decrypted with a key (not the PSB key).

Extensions: .m

Key: usually hex string (length = 13 for most cases, can be different for M2 games, such as 9, and there could be any string rather than just hex), e.g. 523aad2de7132, 38757621acf82, ae3bb93923bf8, Rj9Pegoh4

Seed: key + file name, e.g. 523aad2de7132font_info.psb.m, 38757621acf82voice_info.psb.m

Seed is actually used for generating MT19937 decrypt stream, therefore you must keep file name correct if you just provide key (-k) instead of full seed (-s). e.g. motion_info.psb.m is a good name while motion_info_bak.psb.m is bad because you should never change it.

If you use -k, FreeMote just uses the current file name. Error occurs if you renamed the file.

Header: mdf\0 (mfl\0 etc.)

Structure:

Position Content Value
0 Signature mdf\0
4 original size (uint)
8 Zlib compress header (Encrypted)
10 Zlib compressed content (Encrypted)

Solution:

EmtConvert mpack {file} -k {key} -l 131 note: -l (length) is the key buffer length (how many bytes generated from a key), usually 131, but could be any other value especially for M2 games (such as 97)

PsbDecompile info-psb {file} -k {key} -l 131 (only for archive PSB)

PsBuild info-psb {json file} (only for archive PSB)

LZ4

Compressed using LZ4 Frame. Can be directly decompressed with lz4.exe (with Frame support).

Header: 0x184D2204 (LZ4 Frame header)

Extensions: .lz4, .psb

Solution:

EmtConvert pack -s LZ4 {file}

PsbDecompile {file}

PsBuild {file}

PSZ

Bascially same as MDF(pure).

Header: PSZ\0

Extensions: .psz

Structure:

Position Content Value
0 Signature PSZ\0
4 compressed size (int)
8 original size (uint)
12 none (int)0
16 Zlib compress header 78 9C (fast) or 78 DA (optimal)
18 Zlib compressed content

Solution:

EmtConvert pack -s PSZ {file}

PsbDecompile {file}

PsBuild {file}

Types

PSBs for different purposes have different content structures. FreeMote identifies their types, extract and convert the contents to common formats.

Type ID: found in PSB object (root)\id.

Archive

Type ID: archive

Extensions: .psb.m (normal PSB with MDF(MT19937) shell)

FreeMote.PsbType: ArchiveInfo

To unpack/repack, always use PsbDecompile info-psb xxx_info.psb.m or PsBuild info-psb xxx_info.psb.m.json rather than PsbDecompile info-psb xxx_info.psb or PsBuild xxx_info.psb.m.json. It's DIFFERENT. And always keep file name correct (see MDF(MT19937) for reason).

  • PsBuild xxx_info.psb.m.json: Only generate xxx_info.psb.m, xxx_body.bin will not be built.
  • PsBuild info-psb xxx_info.psb.m.json: Generate both xxx_info.psb.m and xxx_body.bin.
  • You can not unpack/repack xxx_body.bin without xxx_info.psb.m!
  • Same logic for PsbDecompile and PsbDecompile info-psb.

{name}_info.psb.m

Shell Type: MDF(MT19937)

used as (file name/position/file length) index of {name}_body.bin

Solution: PsbDecompile info-psb {file} -k {key} -l 131

{name}_body.bin

Plain combination of many PSB files. It's not directly handled by FreeMote tools (always use corresponding info.psb.m).

Extensions: .bin

Shell Type: MDF(MT19937)

Solution:

Automatically extracted when extracting info.psb.m with PsbDecompile info-psb.

if use PsbDecompile info-psb {file} -k {key} -l 131 -a, all psb.m files in body.bin will be decompiled to json.

EmtConvert mdf {.m file} -k {key} -l 131 (for single .m file)

Script (Scn)

Type ID: (none) (WTF M2?)

Extensions: .scn

FreeMote.PsbType: Scn

Image

Type ID: image

Extensions: .psb

FreeMote.PsbType: Tachie

Images (Pimg)

Type ID: (none)

Extensions: .pimg

FreeMote.PsbType: Pimg

Motion

Type ID: motion

Extensions: .psb, .mtn

FreeMote.PsbType: Motion

Motion Source (Mmo)

Type ID: motion

Extensions: .mmo, .emtproj

FreeMote.PsbType: Mmo

Sound Archive

Type ID: sound_archive

Extensions: .psb

FreeMote.PsbType: SoundArchive

Font

Type ID: font

Extensions: .psb

FreeMote.PsbType: BmpFont

Map

Type ID: map

Extensions: .psb(.m)

FreeMote.PsbType: Map

Platforms

PSB for different platforms uses different resource formats.

Spec ID: found in PSB object (root)\spec.

Currently supported platforms (Spec ID/ FreeMote.PsbSpec):

  • common: Unity games
  • krkr: Kirikiri games
  • win: DirectX games
  • ems: WebGL games with emscripten
  • psp: PSP
  • vita: PSV
  • ps4: PS4
  • nx: NSwitch
  • citra: 3DS
  • and: Android

For EMT (motion) PSB, use PsBuild port -p {specID} to convert platforms between common, win, krkr, ems. Other platforms will not be supported.