Jump to content

PBA

From HedgeDocs
Revision as of 08:07, 8 April 2025 by AdelQue (talk | contribs) (Created page with "{{Notice|type=warn|content=WIP Page, just adding to start}} PBA files are bone physics files first found in Sonic Frontiers, and first regularly used in Shadow Generations. The system is capable of using bouncy bones/jiggle physics, ragdolling, and cloth simulation. The format is still relatively unknown and has only been brute forced through hex analysis more than code analysis, and there are unfortunately not many examples files to reference...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Warning
WIP Page, just adding to start


PBA files are bone physics files first found in Sonic Frontiers, and first regularly used in Shadow Generations. The system is capable of using bouncy bones/jiggle physics, ragdolling, and cloth simulation. The format is still relatively unknown and has only been brute forced through hex analysis more than code analysis, and there are unfortunately not many examples files to reference. The below template has lots of unknowns and potentially wrong info.

TODO: Cleanup:

//------------------------------------------------
//--- 010 Editor v12.0.1 Binary Template
//
//      File: 
//   Authors: Ashrindy, AdelQ
//   Version: 0.0.1
//   Purpose: Shadow Gens PhysicalSkeleton
//  Category: 
// File Mask: *.pba
//  ID Bytes: 
//   History: 
//------------------------------------------------


#include "../include.h"

local uint64 dataPos;

typedef struct{
    Vector4 rows[4];
}Matrix4x4<optimize=false>;

typedef struct{
    byte UnkB1; // Always 2 or 1, unknown flag
    byte UnkB2; // Always 0 or 1, unknown flag
    byte UnkB3[2];  // Padding?
    float Unk_f[4];    // Upper/Lower limits of something?
}LimitsStruct<optimize=false>;

typedef struct{
    SetRandomBackColor();
    StringOffset BoneName;
    int unk; // if this is related to collision, this could be an enum for the collision shape
    float unk2; // Physics dampening? Lower values make bones wobble for longer
    Matrix4x4 mat;  // Most likely not a matrix, has parameters that affect gravity, stretch, etc, and possibly capsule/collision bounds(?) but still working through
}CollisionStruct<optimize=false>;   // Has params that affect physics intensity still, maybe general physics

typedef struct{
    SetRandomBackColor();
    StringOffset BoneName;
    byte Unk1[4]; // All known examples are 01 01 14 00. could be bitflags by the looks of it
    int16 LocalParentBoneIndex;    // FF FF if no bone parent
    int16 LocalBoneIndex;
    int16 RealParentBoneIndex; // Usually the parent of this bone on the real skeleton, but can be any bone in practice. Perhaps a reference for the offset transform?
    int16 Unk3;
    LimitsStruct Limits[6]; // Unknown what these limits line up to (Pos to Neg X, Pos to Neg Y, etc)
    float Unk4<hidden=true>; // Align
    Matrix4x4 mat;  // Possibly bone offset matrix relative to RealParentBoneIndex? A: Two quaternions in row 2 and 4?
}
JiggleStruct<optimize=false>; // Handles bone chain relations for bendy/jiggle physics, as well as presumably transform limits

typedef struct{
    // Starting point needs to align to 16 bytes
    local uint64 CurPos = FTell();
    local uint64 AlignCheck = CurPos % 0x10;
    if (AlignCheck)
        FSeek(CurPos + 0x10 - AlignCheck);
    SetRandomBackColor();
    StringOffset BoneName;
    float unk0; // All known examples = 0.01
    int16 unk1<hidden=true>; // Always FF FF
    int16 if_pinned;    // 1 if no parent present. Possibly this bone controls corresponding vertex if 1, versus vertex controls cooresponding bone if 0
    int16 child_idx;    // FF if no child
    int16 parent_idx;   // FF if no parent
    int16 unk2[2]<hidden=true>;  // Always FF FF
    int16 left_idx;
    int16 right_idx;
}cloth_node<optimize=false>;    // Defines up to 4 neighboring bones in a cloth bone grid

typedef struct{
    SetRandomBackColor();
    int16 verts[2];
    float edge_length;
    float unk_factor;   // Normalized, lateral direct connections = 0.5, lateral skip connections = 0.3, vertical direct connections = 1.0. Maybe a stretch/shrink factor?
}cloth_edges<optimize=false>;   // Lagrangian cloth sim edge mesh

typedef struct{
    SetRandomBackColor();
    StringOffset cloth_name;
    float unk1[10];
    int16 unk_count1[2];
    int32 cloth_node_count;
    int32 cloth_edge_count;
    int32 unk3<hidden=true>; // Align
    int64 cloth_node_ptr;
    int64 cloth_edge_ptr;
    local int64 prePos = FTell();
    FSeek(cloth_node_ptr + dataPos);
    cloth_node bones[cloth_node_count];
    FSeek(cloth_edge_ptr + dataPos);
    cloth_edges edges[cloth_edge_count];
    FSeek(prePos);
}ClothStruct<optimize=false>;   

typedef struct{
    SetRandomBackColor();
    char signature[4]<name="Signature">;
    int version <format=hex, name="Version">;
    StringOffset SkeletonName;
    uint32 CollisionCount;
    uint32 JiggleCount;
    uint64 CollisionOffset;
    uint64 JiggleOffset;
    uint32 ClothCount;
    uint32 UnkCount;
    uint64 ClothOffset;
    uint64 UnkOffset;
    FSeek(CollisionOffset + dataPos);
    CollisionStruct CollisionStructs[CollisionCount];
    FSeek(JiggleOffset + dataPos);
    JiggleStruct JiggleStructs[JiggleCount];
    FSeek(ClothOffset + dataPos);
    ClothStruct ClothStructs[ClothCount];
}
ResPhysicalSkeleton<open=true>;

ResBinaryFile file("ResPhysicalSkeleton")<name=Str("%s", FileNameGetBase(GetFileName()))>;
Cookies help us deliver our services. By using our services, you agree to our use of cookies.