OBD:CRSA
|
CRSA - Corpse Array
Related : File types Level files Oni Binary Data
A CRSA file consists of
- a 32-byte header that specifies the size S and the capacity C of the corpse array
- S corpse chunks with actual corpse data (1100 bytes each)
- (C - S) unused corpse chunks integrally set to 0 (1100 bytes each)
The capacity C is always 20. The size of a chunk is not specified in the header : it's fixed by the "universal" bone count in Oni (19 bones).
- the resulting file is completed to a 32-byte multiple with the 0xADDE blank filler
Since the capacity of the array is always the same (20 corpses), CRSA files are all the same size (0x5620 bytes) : actual arrays take up 0x5610 bytes, and the last 16 bytes are filled with the blank filler 0xADDE.
Header
- What's in the header?
- File ID and level ID as usual : 4 bytes each
- A blank field filled with 0xADDE (dead) : 12 bytes
- Array size (number of corpses) duplicated : 2*4 bytes
- Array capacity (maximum number of corpses, always 20) : another 4 bytes
The total size of a header is thus 0x20 = 32 bytes.
- Example
- 00565-.CRSA in level3_Final.dat
Offset | Raw hex/string | Value | Meaning |
---|---|---|---|
0x00 | 01 35 02 00 | 565 | File ID for 00565-.CRSA |
0x04 | 01 00 00 06 | 3 | Level ID |
0x08 0x0C 0x010 |
AD DE AD DE AD DE AD DE AD DE AD DE |
DEAD | blank filler |
0x14 | 11 00 00 00 | 17 | 17 corpses (array size) |
0x18 | 11 00 00 00 | 17 | 17 corpses (array size again) |
0x1C | 14 00 00 00 | 20 | Room for 20 corpses (array capacity) |
Corpses
They make up the actual array. They follow the header directly
- What's in a corpse?
- A space for notes (160 bytes) : often the name of the file the corpse was taken from when packing the array.
- A link to the ONCC (model that should be used for the corpse) : that's 4 bytes as usual.
- Then, 19 bones, each of them defined by absolute orientation and position (unlike in a TRAM, where orientations are relative)
Every bone is (3*3 + 3)*4 = 48 bytes, so that's 19*48 = 912 bytes. - Finally, an axis-aligned bounding box (2*3*4 = 24 bytes)
The total size of a corpse is thus 1100 bytes.
- What's in a bone?
- The absolute orientation is defined in a "heavy" way via an orthonormal trihedron :
- three 3D vectors x, y and z, each of length 1, at right angles with each other, and ordered "directly"
- (like Oni's world axes : if x points left and y points up then z points to front, not back).
- Each one of those vectors is stored as 3 floats (3*4 bytes), first x, then y, then z (so 3*3*4 = 36 bytes in total).
- The absolute position R of a bone (of its parent node, actually) is stored as 3 floats right after the orientation trihedron.
- That's another 12 bytes, so 48 bytes in total.
Reminder : the 2nd coordinate of R aka y is the height; same for x, y and z.
- Example
- first corpse of 00565-.CRSA in level3_Final.dat.
- Offsets are measured from the start of the corpse chunk : add 0x20 for the offset from the start of file.
Offset | Raw hex | Value | Meaning |
---|---|---|---|
0x00 | _lvl_3_Intro_TCL_A_corpse.dat | probably the name of the source file | |
0xA0 | 01 36 02 00 | 566 | Link to 00566-TCTF_lite_1.ONCC |
Offset | Bone | Raw hex | Value/Meaning |
---|---|---|---|
0xA4 0xB0 0xBC 0xC8 |
Pelvis | C1 74 66 3F 00 78 3E 3D 45 AB DD 3E A6 8B 7D 3D 19 73 7F BF EE 67 B0 BC 03 AE DC 3E 82 2C 3D 3D 8D B2 66 BF C5 FA E7 41 2E 2B CB C1 58 B4 45 C1 |
x = (0.900219, 0.046501, 0.432947) y = (0.061901, -0.997850, -0.021534) z = (0.431015, 0.0461850, -0.901162) R = (28.997446, -25.396084, -12.356529) |
0xD4 0xE0 0xEC 0xF8 |
Lt Thigh | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x104 0x110 0x11C 0x128 |
Lt Calf | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x134 0x140 0x14C 0x158 |
Lt Foot | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x164 0x170 0x17C 0x188 |
Rt Thigh | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x194 0x1A0 0x1AC 0x1B8 |
Rt Calf | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x1C4 0x1D0 0x1DC 0x1E8 |
Rt Foot | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x1F4 0x200 0x20C 0x218 |
Mid | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x224 0x230 0x23C 0x248 |
Chest | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x254 0x260 0x26C 0x278 |
Neck | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x284 0x290 0x29C 0x2A8 |
Head | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x2B4 0x2C0 0x2CC 0x2D8 |
Lt Shoulder | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x2E4 0x2F0 0x2FC 0x308 |
Lt Arm | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x314 0x320 0x32C 0x338 |
Lt Wrist | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x344 0x350 0x35C 0x368 |
Lt Fist | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x374 0x380 0x38C 0x398 |
Rt Shoulder | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x3A4 0x3B0 0x3BC 0x3C8 |
Rt Arm | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x3D4 0x3E0 0x3EC 0x3F8 |
Rt Wrist | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
0x404 0x410 0x41C 0x428 |
Rt Fist | ... | x = (, , ) y = (, , ) z = (, , ) R = (, , ) |
Offset | Raw hex | Value | Meaning |
---|---|---|---|
0x434 | D4 22 8C 41 95 50 E9 C1 BC 31 9C C1 | (17.517006, -29.164347, -19.524284) | "minimal" corner of the AABB |
0x440 | 75 E6 14 42 2E 20 B1 C1 07 B1 D3 C0 | (37.225056, -22.140713, -6.615360) | "maximal" corner of the AABB |
Screenshot
The example is the same as above : 00565-.CRSA in level3_Final.dat
The first corpse chunk has been outlined in black.
ONI BINARY DATA |
---|
CONS << Other file types >> DOOR |
CRSA : Corpse Array |
[[OBD:File types/{{{family}}}|{{{family}}} file]] |