PHYS: Difference between revisions

From wowdev
Jump to navigation Jump to search
(One intermediate revision by the same user not shown)
Line 42: Line 42:
=PHYV (version 1+)=
=PHYV (version 1+)=
{{Template:SectionBox/VersionRange|min_expansionlevel=7|min_build=7.0.1.20773}}
{{Template:SectionBox/VersionRange|min_expansionlevel=7|min_build=7.0.1.20773}}
When this chunk is present there seem to be no other following chunks, probably defines a single collider? example: 7vs_detail_nightmareplant01_phys.phys
  struct
  struct
  {
  {
Line 51: Line 52:
  uint32_t phyt; // default: 0
  uint32_t phyt; // default: 0


=BODY, BDY2, BDY3, BDY4=
=BODY, BDY2=
  struct
  struct
  {
  {
Line 64: Line 65:
  /*0x1c*/  float _x1c; // default 1.0
  /*0x1c*/  float _x1c; // default 1.0
  #endif
  #endif
} bodies[];
=BDY3, BDY4=
struct
{
/*0x00*/  unsigned short type; // maps to dmBodyDef type enum. 0 -> 1, 1 -> 0 = dm_dynamicBody, * -> 2. Only one should be of type 0 (root). possibly only 0 and 1.
/*0x02*/  unsigned short boneIndex;
/*0x04*/  vec3 position;
/*0x10*/  unsigned short shapeIndex;
/*0x12*/  char PADDING_b[2];
/*0x14*/  int shapesCount; // shapes_count shapes are in this body.
/*0x18*/  float unk;
  #if version >= 3 // BDY3
  #if version >= 3 // BDY3
  /*0x20*/  char _x20[4]; // default 0x00000000
/*0x1c*/  float _x1c; // default 1.0
  /*0x24*/  char _x24[4]; // default 0x00000000
  /*0x20*/  float drag; // default 0, maybe incorrect
  /*0x24*/  float angularDrag; // default 0, maybe incorrect
  /*0x28*/  float _x28; // default 0.89999998
  /*0x28*/  float _x28; // default 0.89999998
  #endif
  #endif
Line 132: Line 146:
      
      
   struct {
   struct {
   /*0x00*/  uint32_t count_00;              // Mostly 8
   /*0x00*/  uint32_t vertexCount;              // Mostly 8
   /*0x04*/  char unk_04[0x4];
   /*0x04*/  char unk_04[0x4];
   /*0x08*/  uint64_t RUNTIME_08_ptr_data_0;  // = &data[i].unk_0
   /*0x08*/  uint64_t RUNTIME_08_ptr_data_0;  // = &data[i].unk_0
Line 139: Line 153:
   /*0x18*/  uint64_t RUNTIME_18_ptr_data_1;  // = &data[i].unk_1
   /*0x18*/  uint64_t RUNTIME_18_ptr_data_1;  // = &data[i].unk_1
   /*0x20*/  uint64_t RUNTIME_20_ptr_data_2;  // = &data[i].unk_2
   /*0x20*/  uint64_t RUNTIME_20_ptr_data_2;  // = &data[i].unk_2
   /*0x28*/  uint32_t count_28;              // Mostly 24
   /*0x28*/  uint32_t nodeCount;              // Mostly 24
   /*0x2c*/  char unk_2C[0x4];
   /*0x2c*/  char unk_2C[0x4];
   /*0x30*/  uint64_t RUNTIME_30_ptr_data_3;  // = &data[i].unk_3
   /*0x30*/  uint64_t RUNTIME_30_ptr_data_3;  // = &data[i].unk_3
Line 146: Line 160:
    
    
   struct {                                  // NOTE: This is NOT a fixed size. Every entries' size depends on the header entry's value!
   struct {                                  // NOTE: This is NOT a fixed size. Every entries' size depends on the header entry's value!
     vec3 unk_0[header[i].count_00];
     vec3 vertices[header[i].vertexCount];   // The vertices that compose the convex hull mesh, this data is enough to generate the collision mesh
     struct {
     struct {
       char unk_00[0x10];                    // probably a vec4, but really e-07 values en masse
       char unk_00[0x10];                    // probably a vec4, but really e-07 values en masse
Line 152: Line 166:
     char unk_2[header[i].count_10];
     char unk_2[header[i].count_10];
     struct {
     struct {
       char unk_00[4];
       char unk;                              // 1 or -1
     } unk_3[header[i].count_28];
      char vertexIndex;                      // index in vertex list
      char unkIndex0;                        // index into the nodes
      char unkIndex1;                       // index into the nodes
     } nodes[header[i].nodeCount];           // a tree structure that connects the vertices together
   } data[count];
   } data[count];
  } polytopeShapes;
  } polytopeShapes;
Line 184: Line 201:
  /*0x00*/  mat3x4 frameA;
  /*0x00*/  mat3x4 frameA;
  /*0x30*/  mat3x4 frameB;
  /*0x30*/  mat3x4 frameB;
  /*0x60*/  float frequency;
  /*0x60*/  float angularFrequencyHz;
  /*0x64*/  float dampingRatio;
  /*0x64*/  float angularDampingRatio;
  #if version >= 2 // WLJ2
  #if version >= 2 // WLJ2
  /*0x68*/  uint32_t _x68; // default 0
  /*0x68*/  float linearFrequencyHz; // default 0
  /*0x6c*/  uint32_t _x6c; // default 0
  /*0x6c*/  float linearDampingRatio; // default 0
  #endif
  #endif
  } weldJoints[];
  } weldJoints[];
Line 218: Line 235:
  struct
  struct
  {
  {
   char _unk[0x78];
   mat3x4 frameA;
  mat3x4 frameB;
  float lowerLimit;
  float upperLimit;
  float unk0;
  float unk1;
  float unk2;
  float unk3;
  } prismaticJoints[];
  } prismaticJoints[];


Line 225: Line 249:
  struct
  struct
  {
  {
   char _unk[0x70];
   mat3x4 frameA;
  mat3x4 frameB;
  float lowerAngle;
  float upperAngle;
  float unk0;
  uint32 unk1;
  } revoluteJoints[];
  } revoluteJoints[];



Revision as of 16:14, 14 February 2020

This section only applies to versions ≥ Mists.

.phys files are chunked. The files are used by Blizzard's Domino physics engine which got added to WoW in the fourth expansion (MoP). In build Mists (5.0.1.15464), there is one .phys file "item/objectcomponents/waist/buckle_panstart_a_01.phys". .phys files are an extension to M2s. The M2 requests a .phys file to be loaded by having GlobalModelFlags & 0x20 set.

The main PHYS chunk is followed by an unordered sequence of unique chunks of the other types.

// vec*: * floats
// mat*x*: * times * floats.
  • 1 phys
  • n body
    • n shapes
      • 1 box
      • 1 capsule
      • 1 sphere
      • 1 polytope (version 3+)
      • 1 (tree mesh [*])
      • 1 (height field [*])
  • n joints
    • 1 weld
    • 1 spherical
    • 1 shoulder
    • 1 distance (version 2+)
    • 1 revolute (version 2+)
    • 1 prismatic (version 2+)
    • 1 (mouse [*])

[*] supported by domino, but not available in wow

One body is connected to one bone. Bodies are connected via joints. A joint is of type weld, spherical or shoulder. A body is constructed out of shapes. A shape is a box, capsule or sphere.

PHYS

 short version;
 // since Mists (5.0.1.15???): 0
 // since Legion (7.0.1.20773): 1
 // since Legion (7.0.1.20979): 2
 // since Legion (7.0.1.21063): 2* -- not a different version in file or client parsing, but changed semantics and chunk names
 // since Legion (7.0.3.21287): 3
 // since Legion (7.0.3.21846): 4
 // since Legion (7.3.0.24500): 5 -- this version does not change anything in parsing. it likely handles some existing field differently

Loading is partially backwards compatible and fills up with default values if loading older versions. Since version 2* it no longer reuses chunk identifiers but has separate identifiers for versions (BDY2, SHP2, WLJ2). It still is able to parse old ones, and fills up with defaults.

PHYV (version 1+)

This section only applies to versions ≥ Legion (7.0.1.20773).

When this chunk is present there seem to be no other following chunks, probably defines a single collider? example: 7vs_detail_nightmareplant01_phys.phys

struct
{
  float _unk[0x6];
} phyv[];

PHYT (version 1+)

This section only applies to versions ≥ Legion (7.0.1.20773).
uint32_t phyt; // default: 0

BODY, BDY2

struct
{
/*0x00*/  unsigned short type; // maps to dmBodyDef type enum. 0 -> 1, 1 -> 0 = dm_dynamicBody, * -> 2. Only one should be of type 0 (root). possibly only 0 and 1.
/*0x02*/  char PADDING_a[2];
/*0x04*/  vec3 position;
/*0x10*/  unsigned short modelBoneIndex;
/*0x12*/  char PADDING_b[2];
/*0x14*/  int shapes_base; // starting at shapes[shapes_base]
/*0x18*/  int shapes_count; // shapes_count shapes are in this body.
#if version >= 2 // BDY2
/*0x1c*/  float _x1c; // default 1.0
#endif
} bodies[];

BDY3, BDY4

struct
{
/*0x00*/  unsigned short type; // maps to dmBodyDef type enum. 0 -> 1, 1 -> 0 = dm_dynamicBody, * -> 2. Only one should be of type 0 (root). possibly only 0 and 1.
/*0x02*/  unsigned short boneIndex;
/*0x04*/  vec3 position;
/*0x10*/  unsigned short shapeIndex;
/*0x12*/  char PADDING_b[2];
/*0x14*/  int shapesCount; // shapes_count shapes are in this body.
/*0x18*/  float unk;
#if version >= 3 // BDY3
/*0x1c*/  float _x1c; // default 1.0
/*0x20*/  float drag; // default 0, maybe incorrect
/*0x24*/  float angularDrag; // default 0, maybe incorrect
/*0x28*/  float _x28; // default 0.89999998
#endif
#if version >= 4 // BDY4
/*0x2c*/  char _x2c[0x04]; // default 0x00000000
#endif
} bodies[];

SHAP, SHP2

struct
{
/*0x00*/  short shapeType;
  enum
  {
    box = 0,      // BOXS
    capsule = 1,  // CAPS
    sphere = 2,   // SPHS
#if version >= 3
    polytope = 3, // PLYT
#endif
  };
/*0x02*/  short shapeIndex; // into the corresponding chunk
/*0x04*/  char unk[4];
/*0x08*/  float friction;
/*0x0c*/  float restitution;
/*0x10*/  float density;
#if version >= 2 // SHP2
/*0x14*/  uint32_t _x14; // default 0
/*0x18*/  float _x18; // default 1.0
/*0x1c*/  uint16_t _x1c; // default 0
/*0x1e*/  uint16_t _x1e; // no default, padding?
#endif
} shapes[];

shapes

BOXS

struct
{
/*0x00*/  mat3x4 a;
/*0x30*/  vec3 c;
} boxShapes[];

CAPS

struct
{
  vec3 localPosition1;
  vec3 localPosition2;
  float radius;
} capsuleShapes[];

SPHS

struct
{
  vec3 localPosition;
  float radius;
} sphereShapes[];

PLYT (version 3+)

This section only applies to versions ≥ Legion (7.0.3.21287).

This chunk does it's own array handling since the second part of the chunk is raw data. Instead of splitting in a header and a data chunk, it is combining both parts. The header has fixed size entries, the data block has entries of size based on the corresponding header entry. The header also has fields that are only set on runtime which should be 0 in file and will be a pointer to the corresponding data upon loading.

struct {
/*0x00*/  uint32_t count;
    
  struct {
  /*0x00*/  uint32_t vertexCount;               // Mostly 8
  /*0x04*/  char unk_04[0x4];
  /*0x08*/  uint64_t RUNTIME_08_ptr_data_0;  // = &data[i].unk_0
  /*0x10*/  uint32_t count_10;               // Mostly 6
  /*0x14*/  char unk_14[0x4];
  /*0x18*/  uint64_t RUNTIME_18_ptr_data_1;  // = &data[i].unk_1
  /*0x20*/  uint64_t RUNTIME_20_ptr_data_2;  // = &data[i].unk_2
  /*0x28*/  uint32_t nodeCount;               // Mostly 24
  /*0x2c*/  char unk_2C[0x4];
  /*0x30*/  uint64_t RUNTIME_30_ptr_data_3;  // = &data[i].unk_3
  /*0x38*/  float unk_38[6];                 // not sure if floats: has e-08 values
  } header[count];
  
  struct {                                   // NOTE: This is NOT a fixed size. Every entries' size depends on the header entry's value!
    vec3 vertices[header[i].vertexCount];    // The vertices that compose the convex hull mesh, this data is enough to generate the collision mesh
    struct {
      char unk_00[0x10];                     // probably a vec4, but really e-07 values en masse
    } unk_1[header[i].count_10];
    char unk_2[header[i].count_10];
    struct {
      char unk;                              // 1 or -1
      char vertexIndex;                      // index in vertex list
      char unkIndex0;                        // index into the nodes
      char unkIndex1;                        // index into the nodes
    } nodes[header[i].nodeCount];            // a tree structure that connects the vertices together
  } data[count];
} polytopeShapes;

joints

JOIN

struct JOINEntry
{
  unsigned int bodyAIdx;
  unsigned int bodyBIdx;
  char unk[4];
  enum
  {
    sphericalJoint = 0,
    shoulderJoint = 1,
    weldJoint = 2,
#if version >= 2
    revoluteJoint = 3,
    prismaticJoint = 4,
    distanceJoint = 5,
#endif
  };
  short jointType;
  short jointId; // reference into the corresponding chunk entries.
} joints[];

WELJ, WLJ2

struct
{
/*0x00*/  mat3x4 frameA;
/*0x30*/  mat3x4 frameB;
/*0x60*/  float angularFrequencyHz;
/*0x64*/  float angularDampingRatio;
#if version >= 2 // WLJ2
/*0x68*/  float linearFrequencyHz; // default 0
/*0x6c*/  float linearDampingRatio; // default 0
#endif
} weldJoints[];

SPHJ

struct SPHJEntry
{
  vec3 anchorA;
  vec3 anchorB;
  float frictionTorque;
} sphericalJointEntries[];

SHOJ

Note that even though this chunk is handled differently since version 2, it does not have a version 2* chunk name.

struct SHOJEntry
{
  mat3x4 frameA;
  mat3x4 frameB;
  float lowerTwistAngle;
  float upperTwistAngle;
  float coneAngle;
#if version >= 2
  char _x6c[8]; // NO BACKWARDS COMPATIBILITY as of Legion (7.0.1.20979) and Legion (7.3.0.24931)! client always assumes new size!
#endif
} shoulderJoints[];

PRSJ (version 2+)

This section only applies to versions ≥ Legion (7.0.1.20979).
struct
{
  mat3x4 frameA;
  mat3x4 frameB;
  float lowerLimit;
  float upperLimit;
  float unk0;
  float unk1;
  float unk2;
  float unk3;
} prismaticJoints[];

REVJ (version 2+)

This section only applies to versions ≥ Legion (7.0.1.20979).
struct
{
  mat3x4 frameA;
  mat3x4 frameB;
  float lowerAngle;
  float upperAngle;
  float unk0;
  uint32 unk1;
} revoluteJoints[];

DSTJ (version 2+)

This section only applies to versions ≥ Legion (7.0.1.20979).
struct
{
  char _unk[0x1c];
} distanceJoints[];