Major improvements to VPP, PEG, and ASM parsers: vpp.xscript: - Support all VPP versions (4-10) for Saints Row 1-4 and Red Faction - Add container type detection (str2, packfile, etc.) - Improved compression handling (zlib, LZO, auto-detection) - Better recursive parsing of nested archives peg.xscript: - Full PEG texture container parsing - Support for multiple texture formats (DXT1, DXT3, DXT5, etc.) - Xbox 360 and PC format variants asm.xscript: - Animation state machine container parsing New format definitions: - anim.xscript: Animation data - audio.xscript: Audio containers (bank files) - mesh.xscript: 3D mesh geometry - morph.xscript: Morph targets - rig.xscript: Skeletal rigs - sim.xscript: Simulation data - zone.xscript: Level zone data Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
127 lines
3.0 KiB
Plaintext
127 lines
3.0 KiB
Plaintext
// Volition Rig/Skeleton Format
|
|
// Used by: Saints Row 3/4, Red Faction series
|
|
// Contains bone hierarchy for character animation
|
|
|
|
type volition_rig ui("Volition Rig", root) byteorder LE
|
|
{
|
|
criteria {
|
|
require _ext == "rig_pc" || _ext == "rig_xbox2" || _ext == "rig_ps3";
|
|
// Rig files typically have reasonable bone counts (1-200)
|
|
bone_count_check = u32at(0);
|
|
require bone_count_check > 0 && bone_count_check < 500;
|
|
}
|
|
|
|
is_xbox = ends_with(_ext, "xbox2");
|
|
is_ps3 = ends_with(_ext, "ps3");
|
|
|
|
if (is_xbox) {
|
|
set_name("Rig (Xbox 360)");
|
|
parse_here("volition_rig_be");
|
|
} else if (is_ps3) {
|
|
set_name("Rig (PS3)");
|
|
parse_here("volition_rig_be");
|
|
} else {
|
|
set_name("Rig (PC)");
|
|
parse_here("volition_rig_impl");
|
|
}
|
|
}
|
|
|
|
type volition_rig_be ui("Rig") byteorder BE
|
|
{
|
|
parse_here("volition_rig_impl");
|
|
}
|
|
|
|
type volition_rig_impl ui("Rig")
|
|
{
|
|
// Rig header - 36 bytes of padding/reserved data
|
|
skip(36);
|
|
|
|
u32 bone_count ui("Bone Count");
|
|
u32 rig_flags ui("Flags");
|
|
u32 rig_value ui("Value");
|
|
|
|
// Parse bone data
|
|
if (bone_count > 0 && bone_count < 500) {
|
|
bone_idx = 0;
|
|
repeat(bone_count) {
|
|
i16 parent_id;
|
|
skip(2); // padding
|
|
f32 pos_x;
|
|
f32 pos_y;
|
|
f32 pos_z;
|
|
f32 rot_x;
|
|
f32 rot_y;
|
|
f32 rot_z;
|
|
f32 rot_w;
|
|
|
|
ctx_set("_rig_bone_idx", bone_idx);
|
|
ctx_set("_rig_parent_id", parent_id);
|
|
ctx_set("_rig_pos", pos_x + ", " + pos_y + ", " + pos_z);
|
|
bone_entry = bytesat(0, 1) |> parse volition_rig_bone;
|
|
push("bones", bone_entry);
|
|
bone_entry = 0;
|
|
|
|
bone_idx = bone_idx + 1;
|
|
}
|
|
}
|
|
|
|
// Bone names at end (null-terminated strings)
|
|
names_start = pos();
|
|
remaining = size() - pos();
|
|
if (remaining > 0) {
|
|
name_idx = 0;
|
|
while (pos() < size() && name_idx < bone_count) {
|
|
bone_name = cstring();
|
|
if (len(bone_name) > 0) {
|
|
ctx_set("_rig_name_idx", name_idx);
|
|
ctx_set("_rig_bone_name", bone_name);
|
|
name_entry = bytesat(0, 1) |> parse volition_rig_bone_name;
|
|
push("bone_names", name_entry);
|
|
name_entry = 0;
|
|
name_idx = name_idx + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
total_bones = bone_count ui("Total Bones");
|
|
file_size = size() ui("File Size");
|
|
}
|
|
|
|
type volition_rig_bone ui("Bone")
|
|
{
|
|
idx = ctx_get("_rig_bone_idx");
|
|
parent = ctx_get("_rig_parent_id");
|
|
position = ctx_get("_rig_pos");
|
|
|
|
set_name("Bone " + idx);
|
|
index = idx ui("Index");
|
|
parent_id = parent ui("Parent ID");
|
|
pos_display = position ui("Position");
|
|
}
|
|
|
|
type volition_rig_bone_name ui("Bone Name")
|
|
{
|
|
idx = ctx_get("_rig_name_idx");
|
|
name = ctx_get("_rig_bone_name");
|
|
set_name(name);
|
|
index = idx ui("Index");
|
|
bone_name = name ui("Name");
|
|
}
|
|
|
|
// Nested type for VPP parsing
|
|
type volition_rig_nested ui("Rig") byteorder LE
|
|
{
|
|
file_name = ctx_get("_vpp_file_name");
|
|
set_name(file_name);
|
|
|
|
is_xbox = ctx_get("_vpp_is_xbox");
|
|
is_ps3 = ctx_get("_vpp_is_ps3");
|
|
|
|
// Use truthiness check instead of == 1 for boolean context values
|
|
if (is_xbox || is_ps3) {
|
|
parse_here("volition_rig_be");
|
|
} else {
|
|
parse_here("volition_rig_impl");
|
|
}
|
|
}
|